2

バグを追跡していて、非常に奇妙な動作に遭遇しました。ポインターのセットがあり、それらを1つずつ消去すると、最初のポインターが消去されますが、別のポインターを消去するとセグメンテーション違反が発生します。私が使う

   size_type erase( const key_type& key );

したがって、イテレータを使用することはできません。私のデバッガーは、コールスタックで次のことを示しています。

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);
}

ベース cSubscriber 抽象クラスには、仮想デストラクタがあります。

  virtual ~cSubscriber()
  {
      eventSystem.unsubscribe(this);
  }

何か案は?どうすれば segfault が発生するのかわかりません。そのような要素がない場合、消去は 0 を返すだけです。それとも、空のコンテナから何かを消去しようとするとクラッシュするのでしょうか? (3つの異なるポインターを追加した後、セットのサイズが2つしかない場合、別のバグがありますが、それは別の話です)。

4

1 に答える 1

5

無効なアドレスを渡すstd::set<SOMETHING*>::erase()と、渡された値とコンテナ内の値を比較しようとすると、segfault が発生します。

例えば:

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

std::set<int*,IntPtrComparer> a;
a.insert(new int);
a.erase(NULL);

アップデート

コメントに基づく

デフォルトのコンパレーターを再定義しておらず、デフォルトのコンパレーターはポインターを逆参照していないため、唯一の方法はあなたstd::setが壊れていることです。

内部的にstd::setは、バイナリ ツリーとして実装されます。これは、値を見つけてそれを消去する方法に多くのポインターがあることを意味します。が破損している場合std::set、これらのポインタの一部が無効なメモリ アドレスを指します。この無効なメモリ アドレスは、比較された値の参照(ポインタの参照)を に渡すために使用されます。ポインターへの参照を受け取り、参照を逆参照してポインター値を取得します。cSubscriber* & conststd::lessstd::less

このように、 内の無効なメモリは にstd::setしか表示されませんでした。これは、実際には無効なメモリに触れていないstd::lessためです。std::set無効なメモリ アドレスを、std::lessそれを開いてsegfaultを取得した貧しい人に与えました。

つまり、参照の代わりにコピーを使用するコンパレーターを作成するとstd::set、ポインター値をコピーしてコンパレーターに渡そうとすると、破損が内部に現れるということです。

于 2013-02-06T18:19:28.553 に答える