3

ポインターを含むクラスがあり、クラスは何も継承しません

class MyClass
{
public:
MyClass();
~MyClass();

private:
//i have pointers here
};
MyClass::~MyClass()
{
print("destroyed..");
}

今、私はこのクラスを次のようにベクトルのポインターとして使用する必要があります:

vector<MyClass*> classes;

ここにいくつかのクラスをプッシュしますが、要素を削除すると:

classes.remove(index);

デストラクタが呼び出されず、メモリ リークが発生していると思います。
では、デストラクタを呼び出すにはどうすればよいですか

4

7 に答える 7

3

ポインターのベクトルは、ポインターがdelete削除またはクリアされたときに、ポインターに対して何もしません。ベクトルは、ポインターが動的に割り当てられているかどうかを認識できません。電話するのは仕事じゃないdelete

必要に応じdeleteて、ポインターを呼び出すのはあなた次第です。質問には、それが必要かどうかを判断するのに十分な詳細がありません (指しているオブジェクトがどのように割り当てられているかを示していません)。しかし、メモリリークがあると主張しているので、これはそれらが動的に割り当てられていることを示している可能性があります. 当面の解決策は、delete を呼び出すことです。

delete *it;
classes.erase(it); // vector has no remove member function

より安全な解決策は、 などの一意の所有権を持つスマート ポインターを格納することstd::unique_ptr<MyClass>です。標準ライブラリは、共有所有権と弱い所有権のスマート ポインターも提供します。スマート ポインターを参照してください。

上記のすべては、実際にポインターを格納する必要があることを前提としています。一般に、値を保存する方が安全で明確です。

std::vector<MyClass> classes; // but don't call it "classes". A vector stores objects.
于 2013-09-09T06:27:50.300 に答える
2

std::vector<MyClass*>これが、そもそも使用を避けるべき理由の 1 つです。それに接続された醜いメモリ管理があり、それはそれほど簡単ではありませんclasses.remove(index);

基本的に、このポインターをローカル変数として使用するか、ベクトルに入れるかに関係なく、すべてのnewadeleteを呼び出す必要があり、すべてnew[]の aを呼び出す必要があります。delete[]

vector<MyClass*> vec;
vec.push_back(new MyClass());     // <-- object has been created
...
delete classes[index];            // <-- object shall be destructed
// the delete call will automatically invoke the destructor if needed
...
// now you can remove the dangling pointer from the vector

オブジェクトが破棄されると、このオブジェクトへの (古い) 参照は無効になり、そのような参照 (ダングリング ポインター) を使用してこのオブジェクトにアクセスしようとすると、未定義の動作が発生することに注意してください。

于 2013-09-09T06:31:13.260 に答える
1

まず、std::vectorはありません。removeおそらく を意味しeraseます。

次に、delete削除するものを手動で呼び出す必要があります。

vector<MyClass*> classes;
auto iter = <iterator to index to remove>;
delete *iter;;
classes.erase(iter);

または、このすべての問題を回避するには、std::unique_ptr<MyClass>.

于 2013-09-09T06:30:51.377 に答える
0

アプリケーションが終了する前、またはクラス オブジェクトが から削除された後に、ポインタを手動で削除する必要がありますvector

// Delete all
vector<MyClass*>::iterator it = classes.begin();
while (it != classes.end()) {
    delete *it;
    it = classes.erase(it);
}

ヒント:次のようなスタック構成のポインターを追加しないでください。

MyClass m;
classes.push_back(&m);

編集:他のメンバーが提案したように、より良い解決策は次のとおりです。

MyClass m(/* ... */);
vector<MyClass> classes;
classes.push_back(m);

ただし、クラスに new で作成されたポインター データ メンバーがある場合は特に、コピー コンストラクターを適切に実装する必要があることに注意してください。

于 2013-09-09T06:31:06.960 に答える
0

ベクターから削除する前に、ホール MyClass* ポインターへの一時ポインターを作成します。

vector<MyClass*> classes;

//push some classes in here but
//when i remove an element
MyClass* temp = classes[index];
classes.remove(index);

// call delete temp;  if you want to call the destructor thus avoid memory leak.
delete temp;

メモリ リークを回避するには、ヒープ オブジェクトの制御を決して失わないように注意してください。オブジェクトを解放する前に、ヒープ オブジェクトへのポインタまたは参照を常に保持してください。

于 2013-09-09T06:32:51.630 に答える
0

内部のポインタが指すオブジェクトの存続期間を管理する責任を誰が負っているのかは不明ですclasses。ed ポインターをプッシュnewしたか、自動ストレージ オブジェクトのアドレスをプッシュしましたか?

前者を実行した場合はdelete、ポインタを削除する前に手動でポインタを削除する必要があります。それ以外の場合、後者を行った場合は、そのままにしておくことができます。ポイント先のオブジェクトをそのままにしておくと、それぞれのスコープを離れるときに自分自身が破壊されます。newed ポインターと非ed ポインターが混在していてnew、その可能性が思ったほど遠くない場合は、悪魔が鼻から飛び出すような未定義の振る舞いをしていることは間違いありません。

ポインターが関係するこのような状況は非常にあいまいです。一般的には、ポインターをまったく使用せず、std::vectorストアを単純なオブジェクトにすることをお勧めします。これにより、オブジェクトの有効期間の管理がはるかに簡単になり、宣言を作成するだけで十分です。

vector<MyClass> classes;  // Do this instead
于 2013-09-09T06:32:53.750 に答える
0

ベクターをアイテムのマネージャーにしたいようです。
boost::ptr_vector クラスを見てください
。基本的には std::vector クラスのラッパーです。
このベクトルがこれらのポインターの「ホルダー」であることを宣言し、このコンテナーからそれらを削除する場合は、それらを削除する必要があります。

#include <boost/ptr_container/ptr_vector.hpp>
...
boost::ptr_vector<MyClass> myClassContainer;  
myClassContainer.push_back(new MyClass());
myClassContainer.clear(); // will call delete on every stored object!
于 2013-09-09T08:18:59.797 に答える