c++ - 'vector iterators incompatible' -
this question has been asked number of times on so, answers not apply situation, afaict. following piece of code triggering error upon hitting i != std::end(observers_);
.
void visualgeometry::signalpoppointflags(const point_2r& p, const uint32_t msec_delay) const { for(auto = std::begin(observers_); != std::end(observers_); ++i) (*i)->slotpoppointflags(p, msec_delay); }
looking <vector>
, following triggers error:
void _compat(const _myiter& _right) const { // test compatible iterator pair if (this->_getcont() == 0 || this->_getcont() != _right._getcont()) { // report error _debug_error("vector iterators incompatible"); _scl_secure_invalid_argument; } }
since not comparing iterators different containers, seems first check this->_getcont() == 0
might problem, i'm not sure how tell.
the same problem occurs if swap out begin(vec)/end(vec) vec.begin()/vec.end().
i'm little lost how can happen. advice on how move forward debugging this?
the visualgeometry class designed forward signals receives onward whichever objects watching it. here relevant code snippets:
class visualgeometry : public igeometryobserver, public iobservablegeometry { public: void slotpushsegmentflags(const segment_2r& s, const uint32_t flags, const uint32_t msec_delay = 0) override; void slotpopsegmentflags(const segment_2r& s, const uint32_t msec_delay = 0) override; void signalpushsegmentflags(const segment_2r& s, const uint32_t flags, const uint32_t msec_delay = 0) const override; void signalpopsegmentflags(const segment_2r& s, const uint32_t msec_delay = 0) const override; /* snip */ private: std::vector<igeometryobserver*> observers_; }; void visualgeometry::slotpushsegmentflags(const segment_2r& s, const uint32_t flags, const uint32_t msec_delay) { signalpushsegmentflags(s, flags, msec_delay); } void visualgeometry::slotpoppointflags(const point_2r& p, const uint32_t msec_delay) { signalpoppointflags(p, msec_delay); } /* etc... */
the first thing check see if modifying vector
iterating on iterate on it.
see if eliminates problem:
void visualgeometry::signalpoppointflags(const point_2r& p, const uint32_t msec_delay) const { auto obs = observers_; for(auto = std::begin(obs); != std::end(obs); ++i) (*i)->slotpoppointflags(p, msec_delay); }
dealing kind of problem tricky, , sign have design problem.
in general, when calling sequence of callbacks, if callback has way reach sequence iterating on , change or members, need add in lifetime management code, , determine means callback sent when 1 being sent, , means if callbacks installed or uninstalled while callbacks being called.
a simple rule "you don't callbacks if installed while callbacks being installed", if uninstall callback, not called.
to produce effect, callbacks tend containers of weak_ptr
s std::function
s. when install callback, pass in std::function
, copy shared_ptr
. spawn weak_ptr
off that, , store in callback container.
i return shared_ptr
code installing callback. shared_ptr
lifetime token: long (or copies of it) valid, continue make callbacks on it.
in broadcast function, first sweep container obsolete weak_ptr
s, copy container local std::vector<std::weak_ptr<std::function<void(message)>>>
.
i iterate on container, doing .lock()
std::shared_ptr<std::function<void(message)>>
, if valid calling it.
if broadcast triggered when i'm broadcasting, happens. (if happens often, i'll blow stack, problem). if adds callback, i'm fine. if removes callback, i'm fine.
if things multi-threaded, not locked when iterating on local std::vector
, locked while clearing weak_ptr
s aren't valid, , when cloning sequence of weak_ptr
s, or when adding/removing callbacks vector<weak_ptr<function<...>>>
.
Comments
Post a Comment