1

以下の例では

class X
{
    int *r;
public: 
    X() {
        cout << "X is created";
        r = new int[10];
    };
    ~X() {
        cout<< "X is destroyed";
        delete [] r;
    };
};
class Y
{
public: 
    Y() {
        X x;
        throw 44;
    }; 
    ~Y() {
        cout << "Y is destroyed";
    };
};

あるサイトからこの RAII の例を入手しましたが、いくつか疑問があります。助けてください。

  1. x のコンストラクターでは、「メモリ割り当てが失敗した場合」というシナリオを考慮していません。
  2. ここで、Y のデストラクタは安全です。y の場合、constructor はメモリを割り当てていません。y コンストラクターでもメモリ割り当てを行う必要がある場合はどうなりますか?
4

2 に答える 2

9

のコンストラクタではXnew失敗すると例外 ( ) がスローされますstd::bad_allocnew[]これは、コンストラクタが完了しないため、オブジェクトの有効期間が開始されないため、デストラクタが呼び出されず (オブジェクトが存在しない)、 と の間に不一致がないことを意味しますdelete[]。(Xユーザー宣言のコピー コンストラクターとユーザー宣言のコピー代入演算子が必要です。これは、実装が提供されているものは、構築が成功し、オブジェクトがコピーまたは代入された場合にこの保証を破るためです。)

ではY、コンストラクターでメモリを割り当て、この割り当てが成功した場合、構築の残りの部分が任意の時点で例外をスローした場合、およびコンストラクターがメモリがデストラクタで解放されることを完了した場合に、このメモリが解放されることを確認する必要があります。 (メモリがオブジェクトの存続期間の長さにわたって持続するように設計されていると仮定します)。

これを簡単にするために、割り当てられたメモリは、メモリを解放することだけを担当するオブジェクトにすぐに渡される必要があります。割り当てられたメモリの複数のブロックへの生のポインタを 1 つのクラスで管理することは、複雑でエラーが発生しやすい管理コードのレシピです。

于 2010-03-20T17:32:43.220 に答える
8

x のコンストラクターでは、「メモリ割り当てが失敗した場合」というシナリオを考慮していません。

その必要はありません。失敗した場合、コンストラクターは をスローしstd::bad_allocます。すなわち:

  1. Y コンストラクターが呼び出されます。
  2. X コンストラクターが呼び出されます。
  3. new int[]割り当てが失敗し、 がスローされますstd::bad_alloc。メモリが割り当てられることはありません。
  4. X は構築を終了していないため、Y コンストラクターは失敗し、Y も構築を終了しません。

したがって、漏れはありません。

ここで、Y のデストラクタは安全です。y の場合、constructor はメモリを割り当てていません。y コンストラクターでもメモリ割り当てを行う必要がある場合はどうなりますか?

あなたはまだ問題ありません。割り当てに失敗すると、 がスローされstd::bad_allocます。その失敗は、クラスを使用する人の責任です。

  1. Y コンストラクターが呼び出されます。
  2. X コンストラクターが呼び出されます。
  3. new int[]割り当ては成功します。
  4. Y コンストラクターは何らかの理由で失敗し、例外をスローする必要があります (たとえば、割り当ての失敗)。
  5. 例外をスローするメカニズムは、コール スタックをアンワインドし、任意のローカル変数 (この場合は X を含む) のデストラクタを呼び出します。
  6. X のデストラクタdelete[]new int[].

繰り返しますが、ここでリソースがリークされることはありません。

複数の割り当てには注意する必要があることに注意してください。すなわち:

class Foo
{
    int * r;
public:
    Foo() {
        r = new int;
        throw myException;
    };
    ~Foo() {
        delete r;
    };
};

現在、リソース リークが発生しています。コンストラクターから例外がスローされると、オブジェクトが完全に構築されることはありません。完全に構築されることはないため、デストラクタが呼び出されることはありません。したがって、漏れrます。

于 2010-03-20T17:32:37.253 に答える