4

私はこのトピックに関する他のいくつかの質問をよく見ましたが、動的に割り当てられたメモリを含むオブジェクトのstlリストとそうでないオブジェクトのstlリストからアイテムを正しく消去する方法に(私の知る限り)対処していません。動的に割り当てられたメモリが含まれています。

オブジェクトのリストを使用したい。たとえば、次のオブジェクトを取り上げます (動的に割り当てられたメモリは含まれません)。

class MyPoint {

public:
    MyPoint(int _x,int _y)
    {
        x = _x;
        y = _y;
    }

private:
    int x;
    int y;

};

したがって、オブジェクトのリスト (それらへのポインターではない) を作成し、それに何かを追加してから、要素を消去します。

list<MyPoint> myList;

myList.push_back(MyPoint(3,4));
myList.push_back(MyPoint(1,2));
myList.push_back(MyPoint(8,8));
myList.push_back(MyPoint(-1,2));

list<MyPoint>::iterator it;

it = myList.begin();
advance(it,2);
myList.erase(it);

私のリストには次のものが含まれています: (3, 4) (1, 2) (-1, 2)

  • 質問 1a: 消去されたオブジェクトに対して他に何かする必要がありますか、それともメモリは処理されますか?

  • 質問 1b: プログラムが終了したら、リストに残っているオブジェクトをどうする必要がありますか? それらをすべて削除して、何らかの方法でメモリを処理する必要がありますか?

さて、N 次元空間で点を許可するクラスの代替バージョンを考えてみましょう。つまり、長さ N の配列を動的に割り当てて、クラス内の N 個のポイントを保持することができます (ここでは問題にならないので、実装は割愛します)。クラスのデストラクタは、'delete' を使用して、動的に割り当てられた配列を削除します。

class MyDynamicPoint {

public:
    MyDynamicPoint(int N)
    {
        points = new int[N];
    }

    ~MyDynamicPoint()
    {
        delete points;
        points = NULL;
    }

private:
    int *points;
};

オブジェクト自体ではなく、オブジェクトへのポインターのリストを作成する場合があります。

list<MyDynamicPoint*> myList;

myList.push_back(new MyDynamicPoint(8));
myList.push_back(new MyDynamicPoint(10));
myList.push_back(new MyDynamicPoint(2));
myList.push_back(new MyDynamicPoint(50));

list<MyDynamicPoint*>::iterator it;

it = myList.begin();
advance(it,2);
myList.erase(it);
  • 質問 2a - 上記は正しいですか? つまり、この新しいバージョンのクラスには動的に割り当てられたメモリが含まれているため、オブジェクト自体ではなく、オブジェクトへのポインターのリストを作成する必要があるということですか?

  • 質問 2b - リストからポインターを消去したばかりですが、オブジェクト内に削除する動的メモリがあるという事実に対処するには、どこで delete を呼び出しますか? それとも、stl list の erase メソッドは、オブジェクトのデストラクタを呼び出して処理しますか?

助けてくれてありがとう、

一番、

アダム

4

4 に答える 4

4

次のように、自動保存期間を持つ(つまり、その存続期間がこのクラスのインスタンスに関連付けられている)データメンバーを持つクラスがある場合:

class MyPoint {
private:
    int x;
    int y;
};

を使用するlist<MyPoint> myList;と、このインスタンスstd::listも自動保存期間のオブジェクトであり、コンテナが破棄されるまでに自動的にクリーンアップされ、コンテナが保持する要素もクリーンアップされます。すべてが面倒を見てくれます。

しかし、後者のバージョンはあまり幸運な選択ではありません...ポインタを保持するコンテナがあるだけでなく、Point動的に割り当てられるクラスのデータメンバーを作成することも決定しました。最初に、呼び出しによって割り当てられたすべてのものは呼び出しによって解放されるべきであり、呼び出しによって割り当てられたものはすべて呼び出しによって解放されるべきであることに注意してnewください。deletenew[]delete[]

この状況では、オブジェクトの構築時にメモリを割り当て、オブジェクトが破棄されたときにメモリをクリーンアップします。

MyDynamicPoint(int N)
{
    points = new int[N];
}
~MyDynamicPoint()
{
    delete[] points;
    points = NULL;
}
private:
int *points;

std::vectorCスタイルの配列の一部または代わりに使用することで同じことを実現できstd::array、メモリ管理を自分で行う必要はありません。

MyDynamicPoint(int N) : points(std::vector<int>(N, 0)) { }

private:
std::vector<int> points;

std::vectorオブジェクトがメモリ管理を代行します。

そして最後に、要素を動的に割り当ててコンテナに格納する場合:

myList.push_back(new MyDynamicPoint(8));

このメモリを自分で解放する必要があります。リストからポインタを消去するだけでは不十分です。

list<MyDynamicPoint*>::iterator it;
...
delete *it;
myList.erase(it);

したがって、達成したいことは何でも、状況が許せば、常に自動保存期間のあるオブジェクトを優先します。手動でメモリ管理を行うことを余儀なくされ、後でメモリリークなどの不快な問題に対処することほど悪いことはありません。

于 2013-03-16T14:52:12.037 に答える
3

質問1a:消去されたオブジェクトに対して他に何かする必要がありますか、それともメモリが処理されますか?

何もする必要はありません。

質問1b:プログラムが終了した場合、リスト内の残りのオブジェクトに対して何かを行う必要がありますか?それらをすべて削除して、どうにかしてそれらの記憶を処理する必要がありますか?

何もする必要はありません。

質問2a-上記は正しいですか?

コードが正しくありません。あなたは三つのルールに違反しています。特に、自動生成されたMyDynamicPointのコピーコンストラクタと代入演算子は、pointsポインタのビット単位のコピーを作成します。のインスタンスをコピーすると、2つのオブジェクトが同じポインタMyDynamicPointを共有することになります。points

  • オブジェクトの1つがスコープ外になると、もう1つは使用できなくなります。
  • 2番目のオブジェクトがスコープ外になると、そのデストラクタはすでに解放されているメモリを解放しようとします。これは未定義の動作です。

つまり、この新しいバージョンのクラスには動的に割り当てられたメモリが含まれるため、オブジェクト自体ではなく、オブジェクトへのポインタのリストを作成する必要があるということですか?

いいえ、それはそれを意味するものではありません。実際、おそらくオブジェクトを値で格納し続ける必要があります。ただし、三つのルールを修正する必要があります。

質問2b-リストからポインタを消去したばかりの場合、オブジェクトに削除される動的メモリがあるという事実に対処するために、どこでdeleteを呼び出すのですか?または、stl listのeraseメソッドは、オブジェクトのデストラクタを呼び出して処理しますか?

生のポインタのリストがあるため、デストラクタは自動的に呼び出されません。これを修正する最も簡単な方法は、オブジェクトを値で格納するか、生のポインターの代わりに使用することstd::unique_ptrですstd::shared_ptr

于 2013-03-16T14:53:14.040 に答える
0

私は次のように動作するはずだと思います

MyPoint* ptr = myList.back();

delete ptr;

myList.pop_back();

また

MyPoint* ptr = myList.back();

delete ptr;

myList.erase(ptr);
于 2013-11-06T04:47:06.837 に答える
0

質問 1 については、何もする必要はありません。オブジェクトを値で保存すると、コンパイラとライブラリがすべてを処理します。

ただし、2 番目のケースのようにポインターを格納する場合は、 でdelete割り当てたポインターが必要です。そうしnewないと、メモリ リークが発生します。

また、イテレータが無効になる可能性があるため、消去を行うにポインタを削除する必要があります。

delete *it;
myList.erase(it);
于 2013-03-16T14:51:06.837 に答える