'vector iterators are incompatible'

This question has been asked several times on SO, but the answers are not applicable to my situation, AFAICT. The following code fragment causes an error immediately after pressing i != std::end(observers_); .

 void VisualGeometry::SignalPopPointFlags(const Point_2r& p, const uint32_t msec_delay) const { for(auto i = std::begin(observers_); i != std::end(observers_); ++i) (*i)->SlotPopPointFlags(p, msec_delay); } 

Looking in the <vector> , the following causes an error:

 void _Compat(const _Myiter& _Right) const { // test for compatible iterator pair if (this->_Getcont() == 0 || this->_Getcont() != _Right._Getcont()) { // report error _DEBUG_ERROR("vector iterators incompatible"); _SCL_SECURE_INVALID_ARGUMENT; } } 

Since I am not comparing iterators from different containers, it seems that the first check for this->_Getcont() == 0 may be a problem, but I'm not sure how to say it.

The same problem occurs if I replace begin (vec) / end (vec) for vec.begin () / vec.end ().

I lost a little how this can happen. Any tips on how to move forward with debugging?

The VisualGeometry class is designed to forward the signals it receives, depending on which objects are viewing it. Here are the 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... */ 
+4
source share
1 answer

The first thing to check is to check if you are changing the vector that you are executing when you iterate over it.

See if this fixes the problem:

 void VisualGeometry::SignalPopPointFlags(const Point_2r& p, const uint32_t msec_delay) const { auto obs = observers_; for(auto i = std::begin(obs); i != std::end(obs); ++i) (*i)->SlotPopPointFlags(p, msec_delay); } 

Dealing with such a problem is complex and is often a sign that you have a design problem.

In general, when calling a callback sequence, if this callback has any way to reach the sequence in which you iterate and change its or its members, you need to add some lifecycle management code and determine what that means for the other callback the call to send when it is sent, and what it means if callbacks are set or removed when callbacks are called.

A simple rule is that "you do not receive callbacks if you were set during the installation of callbacks," but if you delete the callback, you will not receive the call.

To produce this effect, my callbacks usually have containers from weak_ptr to std::function s. When you set the callback, you pass std::function , which you then change to shared_ptr . I weak_ptr from it and save it in the callback container.

Then I return shared_ptr to the code that sets the callback. This shared_ptr is the token of life: as long as it (or its copies) is valid, I will continue to make callbacks.

In my broadcast function, I first expanded my container for the deprecated weak_ptr s, and then copied the container to the local std::vector<std::weak_ptr<std::function<void(message)>>> .

Then I .lock() over this container by doing .lock() to get std::shared_ptr<std::function<void(message)>> , and then if it really calls it.

If the broadcast starts during the broadcast, this happens. (if this happens too often, I will blow my stack, but this is another problem). If someone adds a callback, I'm fine. If someone removes the callback, I'm fine.

If everything is multi-threaded, I am not blocked when repeating over local std::vector , but blocked when releasing weak_ptr , which are invalid, and when cloning a sequence of weak_ptr s or when adding / removing callbacks in vector<weak_ptr<function<...>>> .

+7
source

Source: https://habr.com/ru/post/1497910/


All Articles