简体   繁体   English

'矢量迭代器不兼容'

[英]'vector iterators incompatible'

This question has been asked a number of times on SO, but the answers do not apply to my situation, AFAICT. 这个问题在SO上被多次询问,但答案不适用于我的情况,AFAICT。 The following piece of code is triggering the error immediately upon hitting i != std::end(observers_); 以下代码在命中i != std::end(observers_);立即触发错误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 into <vector> , the following triggers the error: 查看<vector> ,以下内容会触发错误:

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 like the first check for this->_Getcont() == 0 might be the problem, but I'm not sure how to tell. 因为我没有比较来自不同容器的迭代器,所以似乎是第一次检查this->_Getcont() == 0可能是问题,但我不知道this->_Getcont() == 0

The same problem occurs if I swap out begin(vec)/end(vec) for vec.begin()/vec.end(). 如果我为vec.begin()/ vec.end()换掉begin(vec)/ end(vec),也会出现同样的问题。

I'm a little lost as to how this can happen. 关于如何发生这种情况,我有点迷茫。 Any advice on how to move forward with debugging this? 关于如何进行调试的任何建议?

The VisualGeometry class is designed to forward signals that it receives onward to whichever objects are watching it. VisualGeometry类旨在将接收到的信号转发到正在观看它的任何对象。 Here are 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 to check is to see if you are modifying the vector you are iterating over as you iterate over it. 要检查的第一件事是看你是否正在修改迭代它时迭代的vector

See if this eliminates 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 that kind of problem is tricky, and often a sign you have a design problem. 处理这类问题很棘手,而且通常表明您遇到了设计问题。

In general, when calling a sequence of callbacks, if that callback has any way to reach the sequence you are iterating over and change it or its members, you need to add in some lifetime management code, and determine what it means for another callback to be sent when one is currently being sent, and what it means if callbacks are installed or uninstalled while callbacks are being called. 通常,在调用一系列回调时,如果该回调有任何方法可以到达您正在迭代并更改它或其成员的序列,则需要添加一些生命周期管理代码,并确定它对另一个回调的含义当一个当前被发送时发送,以及在调用回调时安装或卸载回调的含义。

A simple rule is that "you don't get callbacks if you are installed while callbacks are being installed", but if you uninstall your callback, you will not get called. 一个简单的规则是“如果在安装回调时安装了”,则不会收到回调,但如果卸载回调,则不会被调用。

To produce this effect, my callbacks tend to be containers of weak_ptr s to std::function s. 为了产生这种效果,我的回调往往是对std::function s的weak_ptr s的容器。 When you install your callback, you pass in a std::function , which I then copy into a shared_ptr . 安装回调时,传入一个std::function ,然后将其复制到shared_ptr I spawn a weak_ptr off that, and store it in my callback container. 我生成了一个weak_ptr ,并将其存储在我的回调容器中。

I then return the shared_ptr to the code that is installing the callback. 然后我将shared_ptr返回到正在安装回调的代码。 This shared_ptr is the lifetime token: so long as it (or copies of it) is valid, I will continue to make callbacks on it. 这个shared_ptr是生命周期令牌:只要它(或它的副本)有效,我将继续对它进行回调。

In my broadcast function, I first sweep my container for obsolete weak_ptr s, then copy the container to a local std::vector<std::weak_ptr<std::function<void(message)>>> . 在我的广播函数中,我首先扫描我的容器以获取过时的weak_ptr ,然后将容器复制到本地std::vector<std::weak_ptr<std::function<void(message)>>>

I then iterate over this container, doing a .lock() to get a std::shared_ptr<std::function<void(message)>> , then if it is valid calling it. 然后我遍历这个容器,执行.lock()来获取std::shared_ptr<std::function<void(message)>> ,然后调用它是有效的。

If a broadcast is triggered when I'm broadcasting, it happens. 如果在我播放时触发广播,则会发生。 (if this happens too often, I'll blow my stack, but that is another problem). (如果这种情况经常发生,我会把我的筹码炸掉,但这是另一个问题)。 If someone adds a callback, I'm fine. 如果有人添加回调,我很好。 If someone removes a callback, I'm fine. 如果有人删除回调,我很好。

If things are multi-threaded, I am not locked when iterating over the local std::vector , but am locked while clearing the weak_ptr s that aren't valid, and when cloning the sequence of weak_ptr s, or when adding/removing callbacks to the vector<weak_ptr<function<...>>> . 如果事情是多线程的,我在迭代本地std::vector时没有被锁定,但在清除无效的weak_ptr时被锁定,并且在克隆weak_ptr序列时,或者在添加/删除回调时到vector<weak_ptr<function<...>>>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM