2011-01-13 11 views
2

私は消去メソッドを呼び出すときに正しいオブジェクトに対して間違ったデストラクタが呼び出されるstlベクトルには本当に奇妙な問題があります。
ベクトルに奇妙な問題があります

for(vector<Category>::iterator iter = this->children.begin(); iter != this->children.end(); iter++) 
    { 
     if((*iter).item == item) 
     { 
      this->children.erase(iter); 
      return; 
     } 
     ------------------------- 
    } 

それが検索されるいくつかのアイテムを持っているベクトルの要素を見つけ、ベクトルからの要素言っ削除し、単純な機能です:
私のコードは次のようになります。私の問題は、イレーズ関数が呼び出され、イテレータが指しているオブジェクトが破棄されているときよりも、間違ったデストラクタが呼び出されていることです。より具体的には、ベクトルの最後の要素のデストラクタが呼び出されており、実際のオブジェクトは削除されていません。したがって、メモリは間違ったオブジェクトから削除されています。これは依然としてベクトルの要素であり、実際のオブジェクトはベクターから削除されますが、それでもメモリは完全に保持されています。あなたは、おそらく標準的なアルゴリズムを使用する必要があります

Category::Category(const Category &from) 
{ 
    this->name = from.name; 
    for(vector<Category>::const_iterator iter = from.children.begin(); iter != from.children.end(); iter++) 
     this->children.push_back((*iter)); 

    this->item = new QTreeWidgetItem; 
} 

デストラクタ

Category::~Category() 
{ 
    this->children.clear(); 
    if(this->item != NULL) 
    { 
     QTreeWidgetItem* parent = this->item->parent(); 
     if(parent != NULL) parent->removeChild(this->item); 
     delete this->item; 
    } 
} 
+1

コピー代入演算子はどのように見えますか? –

+0

動作している最小の例ははるかに歓迎されるでしょう。 – karlphillip

+0

私はコピーアサイメント演算子を持っていない、私は実際にそれを使用していない。 –

答えて

5

要素をベクトルから消去すると、要素の後ろの各要素は(割り当て演算子を使用して)ベクトルの前の点にコピーされます。これが完了すると、ベクトルの最後の要素が破棄されます。これは、あなたの最後の要素が破壊されているのを見る理由になります。 STLを使用するときのルール番号1は、オブジェクトのコピーセマンティクスが正しいことを確認することです。

あなたは代入演算子を書いて検討する必要があります。

Category & operator =(const Category & other); 

これは、オブジェクトをコピーして、ベクターに何回も破壊されます考えると、それは言うほど簡単ではないかもしれないが。

+0

本当に、これはstd :: vectorがどのように動作するかわかりませんでした。私は代入演算子を作成しました。実際にはデストラクタの前に呼び出されます。私はオブジェクトではなくポインタのベクトルに切り替えるべきだと思う。 –

+0

注意しておくと、未処理のポインタがあります。特に、デストラクタを指定すると、そのポインタに対するコピー操作の影響を理解する必要があります。これについて考えると、消去後にベクトルをコピーして元のコードを破棄し、ポインタが削除されます(これはUI要素であるためコピーに新しいウィジェットを作成できないと思います?)今、あなたの要素は、削除されたものを保持しています... – Nim

0


オブジェクトのcostructorは、次のようになります。

私が見ている主な問題は、カテゴリのデストラクタが親ベクトルにそれを削除するよう要求することです。それが正しいとは限りません。デストラクタは、ベクターが既にそれを削除しているときにのみ発生します。

std :: vectorはplacement-newを使用するので、デストラクタを直接呼び出します。私はこの時点でどのような効果がベクターに戻るのか分かりません。

デストラクタからif (parent != NULL) parent->removeChild(this->item)行を削除します。あなたが望むものではありません。

+0

私はその行をダブルテイクしなければなりませんでしたが、これは完全に受け入れられる1つのウィジェットを削除しています... – Nim

+0

@Nim問題は、ベクトルからアイテムを削除すると自動的にそのコンストラクタが呼び出されることです(ポインタではなくオブジェクトのベクトルがあるため、オブジェクトは破壊されます) )。もちろん、「中間」で消去している場合、実際にはコピーがロードされますが、結果は同じになります。アイテムのオブジェクトは削除されます。デストラクタでベクトルに戻り、アイテムを削除するように依頼します。 – CashCow

+0

'removeChild()'は* Qt *インターフェースの一部です。私はそれがベクターからの消去を引き起こすメソッドではないと思います。 – Nim

0

これは予想される動作です。私の実装では、ベクトルから要素を消去するときに、n + 1からendまでの要素が割り当てられ、最後の要素が破棄されます(私はあなたの上で推測しています)。

std::listを使用する場合は、この問題が発生しないようにしてください。

デモ:

#include <iostream> 
#include <vector> 
struct Category 
{ 
     int item; 
     Category(int n=0) : item(n) {} 
     ~Category() { std::cout << "Category " << item << " destroyed\n"; } 
}; 
int main() 
{ 
     std::vector<Category> children(3); 
     children[0] = Category(0); 
     children[1] = Category(1); 
     children[2] = Category(2); 

     int item = 0; 
     std::cout << " beginning the loop \n"; 
     for(std::vector<Category>::iterator iter = children.begin(); 
             iter != children.end(); ++iter) 
     { 
      if(iter->item == item) 
      { 
        children.erase(iter); // prints "Category 2 destroyed"! 
        break; 
      } 
     } 
     std::cout << " loop done \n"; 
} // this will print "Category 1 destroyed" and "Category 2 destroyed" 

そして、はい、明示的なerase/remove_ifがループよりも読みやすいです。