std :: set :: erase(const key_type&key)如何导致段错误?

use*_*947 2 c++ pointers stl set segmentation-fault

我正在跟踪错误,并且遇到了非常奇怪的行为。我有一组指针,当我一一删除它们时,第一个删除了,但是擦除另一个则给了我segfault。我用

   size_type erase( const key_type& key );
Run Code Online (Sandbox Code Playgroud)

所以它不能与迭代器有关。我的调试器向我展示了在调用堆栈中:

0 - std::less<cSubscriber *>::operator() //cSubscriber is an abstract base class and I have a set of cSubscriber *

1 - std::_Rb_tree<cSubscriber*, cSubscriber*, std::_Identity<cSubscriber*>, std::less<cSubscriber*>, std::allocator<cSubscriber*> >::equal_range

2 -  std::_Rb_tree<cSubscriber*, cSubscriber*, std::_Identity<cSubscriber*>, std::less<cSubscriber*>, std::allocator<cSubscriber*> >::erase

3 - std::set<cSubscriber*, std::less<cSubscriber*>, std::allocator<cSubscriber*> >::erase

4 - cEventSystem::unsubscribe //my function, it is as follows in the class which has the set as its member

cEventSystem::unsubscribe(cSubscriber * ptr)
{
   set.erase(ptr);
}
Run Code Online (Sandbox Code Playgroud)

在基础cSubscriber抽象类中,有一个虚拟析构函数:

  virtual ~cSubscriber()
  {
      eventSystem.unsubscribe(this);
  }
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?我不知道它怎么会导致段错误,当没有这样的元素时,擦除应该只返回0。还是尝试从空容器中擦除某些内容时崩溃?(在添加3个差值指针后,我遇到了另一个错误,即set的大小仅为2,但这是另一个故事)。

And*_*uel 5

如果将无效的地址传递给您std::set<SOMETHING*>::erase(),则在尝试将传递的值与容器中的值进行比较时,它将出现段错误。

例如:

struct IntPtrComparer {
    bool operator()(int* a, int* b) const {
        return *a < *b;
    }
};

std::set<int*,IntPtrComparer> a;
a.insert(new int);
a.erase(NULL);
Run Code Online (Sandbox Code Playgroud)

更新资料

根据评论

由于您没有重新定义默认比较器,并且默认比较器没有取消引用您的指针,因此唯一的方法是您的指针std::set已损坏。

在内部,std::set被实现为二叉树。这意味着它有很多指针来查找和删除值。如果std::set已损坏,则这些指针中的某些指针将指向无效的内存地址。此无效的内存地址将用于将比较值的引用(指针的引用)传递cSubscriber* & conststd::lessstd::less接收到对指针的引用,并将取消对该引用的引用以获取指针值。

这样一来,里面的一个无效的内存std::set并只在出现std::less,因为std::set实际上并没有触及无效的内存,它给了无效的内存地址,我们可怜的家伙std::less打开它,并得到了段错误在它的脸上。

我的全部观点是,如果您创建一个使用副本而不是引用的比较器,则std::set在尝试将指针值复制给比较器时,它的内部将显示损坏。