私はプログラミングに慣れていませんが、Javaで作業した後、私はC++に戻り、ポインタではないクラス変数について少し混乱しています。
混乱は、ヒープ上のデータと必ずしもヒープ上にないデータの組み合わせから生じるように見えます。これは混乱の一般的な原因です。
投稿したコードでは、bars
はポインタではありません。それはクラススコープのため、オブジェクトを含むオブジェクト(testbars
)が破棄されるまで存在します。この場合、testbars
がスタック上に作成されたため、スコープがどれくらい深くネストされているかにかかわらず、スコープから外れると破棄されます。 testbars
が破壊された場合、testbars
のサブオブジェクト(それらが親クラスであるかtestbars
オブジェクトに含まれるオブジェクトであるか)は、その瞬間に明確な順序でデストラクタを実行します。
これはC++の非常に強力な側面です。ネットワーク接続を開き、ヒープ上にメモリを割り当て、データをファイルに書き込む10行のコンストラクタを持つクラスを想像してみましょう。クラスのデストラクタがそれをすべて元に戻したとします(ネットワーク接続を閉じる、ヒープ上のメモリを解放する、ファイルを閉じるなど)。今、このクラスのオブジェクトの作成がコンストラクタの途中で失敗したとします(たとえば、ネットワーク接続がダウンしている)。どのようにして、デストラクタのどの行が成功したコンストラクタの部分を元に戻すかをプログラムが知ることができますか?これを知る一般的な方法はないので、そのオブジェクトのデストラクタは実行されません。
ここで、10個のオブジェクトを含むクラスを想像してください。これらのオブジェクトのコンストラクタは、ロールバックする必要があります(ネットワーク接続を開く、ヒープ上にメモリを割り当てる、データをファイルに書き込むなど)これらのオブジェクトのそれぞれのデストラクタには、アクションをロールバックするために必要なコードが含まれています(ネットワーク接続を閉じる、オブジェクトの割り当てを解除する、ファイルを閉じるなど)。 5つのオブジェクトだけが正常に作成された場合、それらの5つだけを破壊する必要があり、そのデストラクタはその時点で正確に実行されます。
testbars
がヒープ上に作成された場合(new
経由)、delete
を呼び出すと破棄されます。一般に、オブジェクトが作成されたスコープよりも長持ちする理由がない限り、スタック上のオブジェクトを使用する方がはるかに簡単です。
これはFoo::bar
になります。 Foo::bars
は、ヒープ上のオブジェクトを参照するmap
です。つまり、このコード例では、ヒープに割り当てられたオブジェクトを参照するポインタを指します(ポインタはスタックに割り当てられたオブジェクトを参照することもできます)。これらのポインタが参照するオブジェクトを投稿した例では、決してdelete
dであり、これらのオブジェクトはヒープ上にあるため、小さなメモリリーク(オペレーティングシステムがプログラム終了時にクリーンアップする)が発生しています。 STLによると、Foo::bar
のようにはdelete
ポインタのように彼らが破壊されて参照してください。 Boostにはこの問題の解決策がいくつかあります。あなたの場合は、ヒープ上にこれらのオブジェクトを単に割り当てない方が簡単でしょう:
#include <iostream>
#include <map>
using std::map;
using std::cout;
class Foo {
public:
Foo() {
// normally you wouldn't use the parenthesis on the next line
// but we're creating an object without a name, so we need them
bars[0] = Bar();
bars[0].id = 5;
}
~Foo() { }
struct Bar {
int id;
};
void set_bars(map<int,Bar>& b) {
bars = b;
}
void hello() {
cout << bars[0].id << endl;
}
protected:
map<int,Bar> bars;
};
int main() {
Foo foo;
foo.hello();
map<int,Foo::Bar> testbars;
// create another nameless object
testbars[0] = Foo::Bar();
testbars[0].id = 10;
foo.set_bars(testbars);
foo.hello();
return 0;
}
私は "bars.clear();"を追加します。 freeBarsMemory()の最後では、使用するのが少し安全です。 –