web-dev-qa-db-ja.com

new []式がデストラクタを呼び出すのはなぜですか?

C++ 17標準から(ドラフト ここ )、[expr.new]:

new-expressionがクラス型のオブジェクトまたはオブジェクトの配列を作成する場合、アクセスとあいまいさの制御は、割り当て関数、割り当て解除関数、およびコンストラクターに対して行われます。 new-expressionがクラスタイプのオブジェクトの配列を作成する場合、デストラクタが呼び出される可能性があります。

なぜnew[]デストラクタを呼び出しますか?結局new、です。 削除ではありません。

39
thb

バッファ内のオブジェクトの構築で例外がスローされた場合、以前に構築されたオブジェクトを破棄する必要があります。それには、利用可能なデストラクタが必要です。

標準から言及した引用の中で、単語"potentially"を考慮していません。
これは、デストラクタの呼び出しが発生する可能性があることを意味します。そして、配列内のオブジェクトの構築が例外をスローすると、それが起こります

_[class.dtor]/12.4_について言及している _[expr.new]_ からの次の引用と組み合わせると、これは明確になります。

いずれの場合も、呼び出しのコンテキストはオブジェクトの構築のコンテキストです。デストラクタは、new-expressionによって割り当てられた構築済みオブジェクトのdelete-expressionを使用して暗黙的に呼び出されます。呼び出しのコンテキストは、削除式です。 [注:クラス型の配列には、デストラクタが呼び出されるそれぞれのサブオブジェクトがいくつか含まれています。 — end note]デストラクタを明示的に呼び出すこともできます。 デストラクタは、呼び出された場合、または_[expr.new]_、_[class.base.init]_、および_[except.throw]_で指定されている場合、潜在的に呼び出されます。呼び出される可能性のあるデストラクタが削除されているか、呼び出しのコンテキストからアクセスできない場合、プログラムは不正な形式です。

13
P.W

実行中:

#include <iostream>

int counter;

class Destruct
{
public:
    Destruct()
    {
        if (counter++ > 5)
            throw counter;
    }

    ~Destruct()
    {
        std::cout << "Dtor called\n";
    }
};

int main()
{
    try
    {
        new Destruct[10];
    }
    catch (...){}
}

次のような出力が表示されます。

Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
Dtor called
8
Ajay