9

Fooオブジェクトと、そのインスタンスを保持するstd::listがあります。私の問題は、リストに新しいインスタンスを追加すると、最初にctorが呼び出され、次にdtorも呼び出されることです。次に、別のインスタンスのdtor(このポインターによる)。

単一のインスタンスがリストに追加されますが、そのdtor(およびその親)が呼び出されるため、オブジェクトは期待どおりに使用できません。

問題を説明するためのいくつかの簡略化されたコードを次に示します。

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo> li;
    li.push_back(Foo());
}
4

5 に答える 5

14

Fooオブジェクトをpush_back()すると、オブジェクトがリストの内部データ構造にコピーされるため、別のインスタンスのDtorとCtorが呼び出されます。

C ++のすべての標準STLコンテナタイプは、アイテムを値で取得するため、必要に応じてコピーします。たとえば、ベクトルを大きくする必要があるときはいつでも、ベクトル内のすべての値がコピーされる可能性があります。

リスト内のオブジェクトの代わりにポインタを格納したい場合があります。そうすることで、オブジェクトの代わりにポインタのみがコピーされます。ただし、そうすることで、完了したら必ずオブジェクトを削除する必要があります。

for (std::list<Foo*>::iterator it = list.begin(); it != list.end(); ++it) {
    delete *it;
}
list.clear();

または、Boostライブラリなどの「スマートポインタ」クラスを使用することもできます。

于 2009-02-05T08:53:24.963 に答える
4

ここで一時的なFooを作成しています:

li.push_back( Foo() )

push_backは、そのFooを内部データ構造にコピーします。push_backが実行された後、一時的なFooは破棄され、デストラクタが呼び出されます。

早期に破棄したくないクラスメンバーの参照カウントを増やす適切なコピーコンストラクターが必要になります。または、ポインターソリューションを強制するためにプライベートにする必要があります。

于 2009-02-05T08:55:00.280 に答える
2

このオブジェクトを使用して、次のことを理解してください。

class Foo
{
public:
    Foo(int x): m_x(x)
    { 
    std::cout << "Constructed Object: " << m_x << ")\n";
    }
    Foo(Foo const& c): m_x(c.m_x+100)
    {
    std::cout << "Copied Object: " << m_x << ")\n";
    }
    ~Foo()
    {  
    std::cout << "Destroyed Object: " << m_x << ")\n";
    }
};

最初のメイン

std::list<Foo*> li;
li.push_back(Foo(1));

ここでは、一時的なFooオブジェクトを作成し、push_back()を呼び出します。一時オブジェクトがリストにコピーされ、関数が戻ります。このステートメントが完了すると、一時オブジェクトは(デストラクタを介して)破棄されます。リストが破棄されると、リストに含まれるすべてのオブジェクトも破棄されます(Fooはデストラクタを持つオブジェクトであるため、破棄にはデストラクタの呼び出しが含まれます)。

したがって、次のようなものが表示されるはずです。

Constructed Object: 1
Constructed Object: 101
DestroyedObject: 1
DestroyedObject: 101

2番目の例では、次のようになります。

std::list<Foo*> li;
li.push_back(new Foo(1));

ここでは、ヒープ上にオブジェクトを動的に作成します。次に、push_back()を呼び出します。ここでは、ポインターがリストにコピーされるため(ポインターにはコンストラクター/デストラクターがありません)、他に何も起こりません。これで、リストにヒープ上のオブジェクトへのポインターが含まれます。関数が返す場合、他には何も行われません。リストが破棄されると、リストに含まれるオブジェクト(ポインタ)が破棄されます(破棄と削除の微妙な違いに注意してください)が、ポインタにはデストラクタがないため、メモリリークは発生しません。

したがって、次のようなものが表示されるはずです。

Constructed Object: 1
于 2009-02-05T18:29:37.670 に答える
1

ここで実際に行われるのは、渡されたオブジェクトのコピーをリストに格納することです。これは、参照ではなく値で送信するためです。したがって、最初に呼び出されるdtorは、push_backメソッドに渡すオブジェクトで実際に呼び出されますが、それまでに新しいインスタンスが作成され、リストに保存されます。

Fooオブジェクトのコピーを作成したくない場合は、オブジェクト自体ではなく、 Fooオブジェクトへのポインターをリストに格納します。もちろん、それを行うときは、リストの破棄時にメモリを適切に解放する必要があります。

于 2009-02-05T08:58:34.297 に答える
0

インスタンスの代わりにポインタを保持するリストを作成すると、デストラクタが呼び出されるという問題が解決されます。しかし、私はまだそれが起こる理由を理解したいと思います。

#include <iostream>
#include <list>

class Foo
{
public:
    Foo()
    { 
        int breakpoint = 0;
    }
    ~Foo()
    { 
        int breakpoint = 0;
    }
};

int main()
{
    std::list<Foo*> li;
    li.push_back(new Foo());
}
于 2009-02-05T08:53:53.900 に答える