1

ポインターの標準ベクトルがあります。

このベクトルへのイテレータが無効になる可能性があるのは、どのような状況ですか?

オブジェクトが削除されると、それを参照するベクトル反復子が無効になると信じる理由があります。しかし、これは私には正しくないようです。これが Managed .NET のコンテナーの標準的な動作であると私は信じていますが、これは C++ ではうまくいかないように思えます。

for (It = Vec.begin(); It != Vec.end(); It++){
  GoToOtherCode((*It));
}

function GoToOtherCode (ObjectType* Obj){
  delete Obj;
}

これは Iterator It を無効にするべきですか? そうすべきではないように思えますが、デバッグするのが難しい問題で立ち往生しています! (回避策が怖いです-整数インデックスを介してベクトルを反復処理します。(これはうまく機能します...上記が無効化の問題を引き起こしている理由が怖いだけです)。

お時間をいただきありがとうございます。

編集:アドバイスをありがとう。一般的なコンセンサスは、上記のコードは危険ですが、Iterator を無効にしないということです。Visual Studio 2008 デバッガーでエラーが発生したと思います。プロジェクトを翌日開いた後、この無効化の問題がなくなったからです。そのため、コンピューターの多くの場合と同様に、他に何も機能しない場合は、リセットしてみてください。

4

8 に答える 8

8

イテレータを無効にすることはありません。実際には、ベクトルが所有するヒープに割り当てられたオブジェクトを削除する方法です。 clear() メソッドはそれを行いません。これはかなり一般的です:

for (It = Vec.begin(); It != Vec.end(); It++)
  delete *It;

Vec.clear();

削除したばかりのものを使用しようとしなければ、まったく問題ありません。

于 2009-09-30T00:18:04.680 に答える
3

イテレータを無効にするわけではありませんが、ポインター自体は削除されたオブジェクトを指しているままになるため、コードがぶら下がっているポインターでつまずかないようにするために何かをする必要があります。たとえば、ポインタを null 値に設定したりerase、ベクトルから削除された項目を削除するために使用したりできます。

于 2009-09-30T00:11:01.027 に答える
2

*iter私が間違っていなければ、イテレータ逆参照は参照を返すので、代わりに関数にポインタ参照を受け取るようにすることができます。ただし、これはおそらく最善の方法ではありません。

for(It i = vec.begin(); i != vec.end(); i++)
{
    GoToOtherCode(*i);
}

void GoToOtherCode (ObjectType *& pref)
{
    // This *should* set the iterator's copy of the pointer to null
    delete pref;
    pref = 0;
}

次に、ベクトル内のヌルをチェックできます。警告: テストされていないコード。

于 2009-09-30T00:19:43.027 に答える
1

virtual奇妙なこと(そしておそらく破損も)を引き起こす可能性のあることの1つは、デストラクタを持たないクラスから派生したクラスへのインスタンスへのポインタを削除することです。誰かがこれが腐敗を引き起こすのを見たことがあるかどうかはわかりませんが、それが問題を引き起こすことは想像できます。私は次のようなことを考えています:

//----- base.h -----
// nothing declared as virtual here!!
class Base {
public:
  Base();
  ~Base();
};
Base* getPointer();

//----- derived.cpp -----
class Derived: public Base {
public:
  Derived();
  ~Derived();
};
Base* getPointer() {
    return new Derived();
}

//----- main.cpp -----
#include "base.h"
#include <vector>
int main() {
  std::vector<Base*> v;
  v.push_back(getPointer());
  for (std::vector<Base*>::iterator i=v.begin(); i!=v.end(); ++i) {
    delete *i; // Derived::~Derived() is not invoked here
  }
  v.clear();
  return 0;
}

おそらくそうではありませんが、念のために言及したいと思いました。

于 2009-09-30T01:49:28.927 に答える
1

これはあなたのイテレータを無効にするべきではありません - しかし...

ここでの危険は、ObjectType インスタンスを削除したにもかかわらず、Vec ベクトルに元のメモリ位置へのポインターがまだ含まれていることです。ベクターは、インスタンスが削除されたことを知りません。

ベクトル自体は問題ないはずです。無効になった多くの場所を指しているだけです。

于 2009-09-30T00:10:23.277 に答える
0

実際には、ベクトルの再割り当てが行われると、イテレータは無効になります。ベクトルの初期化中に、実際には最初に一部のメモリが予約されますが、このメモリがすべてベクトルによって使い果たされると、ベクトル全体がメモリに再割り当てされ、すべてのイテレータが無効になります。

于 2009-11-09T07:33:36.613 に答える
0

イテレータは無効になりません (要素の順序を変更しない限り)。

しかし、他に 2 つの提案 / ベスト プラクティスがあります。

  1. ベクトルを反復処理するには、ポスト インクリメントの代わりにプリ インクリメントを使用します。ポストインクリメントは、常に現在の要素の一時的なコピーを作成しますが、これはコストがかかる可能性があります! (ポインタの場合は問題ではありません...しかし、常にpre-incを使用する必要があります!)。
  2. プレーン ポインターのベクトルを使用しないでください。参照カウント スマート ポインターのベクトルを使用します。shared_ptrは C++0x に含まれ、現在のほとんどすべての C++ 実装 (VC8、gcc、intel など) には既に含まれています (boost 経由でも利用できます)。スマート ポインターはオブジェクトを所有しているため、その有効期間を観察します (不要になった場合は削除します。そのため、注意する必要はありません...

パフォーマンスへの影響はごくわずかです (1 レベルの間接呼び出しのみ)。

typedef vector<shared_ptr<ObjectType> > MyObjVector;
MyObjVector Vec;

for (It = Vec.begin(); It != Vec.end(); ++It)
{
  GoToOtherCode(*It);
}

function GoToOtherCode (shared_ptr<ObjectType>& PObj)
{
  // no delete needed!
}
于 2009-10-02T08:13:55.707 に答える
0

他の人が述べたように、反復子を呼び出すdeleteと、それが指すデータは削除されますが、ポインター自体は削除されません。ポインター自体を NULL に設定するかerase、ベクターのメソッドを使用してポインターを削除するようにしてください。

コンテナーがポインターのコンテナーである場合、問題が発生する可能性があります。ポインターへのポインターを削除したばかりですが、次はどうすればよいでしょうか? そのメモリにアクセスまたは解放するにはどうすればよいでしょうか。

于 2009-10-01T00:46:07.780 に答える