19

このSOの質問では、この構成によりインスタンスのスタック割り当てが妨げられると述べられています。

class FS_Only {
    ~FS_Only() = delete;  // disallow stack allocation
};

私の質問は、どのように割り当てを防ぐのですか? このインスタンスを明示的または暗黙的に削除することはできないことを理解しています。しかし、それはそれぞれメモリリークまたは実行時エラーにつながると思います。

コンパイラはこれを整理してコンパイラエラーを発生させるのに十分賢いですか? また、なぜこれが必要なのですか?

4

6 に答える 6

36

自動保存期間を持つ変数 (つまり、ローカル変数) のデストラクタは、変数の有効期間が終了したときに実行する必要があります。アクセス可能なデストラクタがない場合、コンパイラはそのような変数を割り当てるコードのコンパイルを拒否します。

基本的に、「スタック割り当て」(ちなみに用語の不正確な選択) と自由ストア割り当ての違いは、ローカル変数ではコンストラクター/デストラクタの呼び出しが常にペアで行われるのに対し、自由ストア割り当てでは、オブジェクトを破壊することなくオブジェクトを構築できることです。 . したがって、デストラクタへのアクセスを防止することにより、コードでその型のローカル変数を割り当てることができなくなります (コンストラクタが実行される場合、デストラクタも実行する必要がありますが、デストラクタがないため、プログラムは拒否されます)。

于 2013-09-17T10:47:35.010 に答える
20

このインスタンスを明示的または暗黙的に削除することはできないことを理解しています。

それ以上に、インスタンスを破棄することはできません。それを削除するかどうかに関係なく。

自動変数 (または必要に応じて「スタック割り当て」) を宣言すると、プログラムが宣言のポイントに到達したときにインスタンスが作成されるだけではありません。また、プログラムがそのブロックを離れたときに破棄されます。削除されたデストラクタでは、それができないため、宣言は許可されません。

これにより、プログラムまたはスレッドの終了時に変数を破棄するコードも生成されるため、静的変数またはスレッドローカル変数を宣言することもできなくなります。

したがって、これらのいずれかを作成する唯一の方法は を使用newすることです。一度作成すると、それを破棄することはできません。ただし、これでスタック割り当てが完全に妨げられるわけではありません。

char memory[sizeof(FS_Only)] alignas(FS_Only);
FS_Only * not_fs = new (memory) FS_Only;

また、なぜこれが必要なのですか?

私の見解では、あなたはそうしないでしょう。強制的なメモリ リークは、オブジェクトが間違ったタイミングで破棄されないようにする恐ろしい方法です。代わりに、 RAIIなどの手法を使用して、動的な有効期間が必要なオブジェクトを管理し、使用後にオブジェクトを削除する責任を負う適切に定義された所有者 (または共有所有者) が常に存在するようにします。C++11 標準ライブラリのスマート ポインターは、出発点として適しています。

于 2013-09-17T11:07:57.730 に答える
6

デストラクタを削除済みとしてマークすると、オブジェクトを破棄できなくなります。スタック上にあるかヒープ上にあるかは問題ではありません。オブジェクトのすべての破棄 (スコープ外に出るか、それを実行するかによって自動的に行われるかどうかに関係deleteなく) は、デストラクタを呼び出します。また、デストラクタの呼び出しを処理するのはコンパイラであるため、デストラクタが削除済みとしてマークされているかどうかを認識し、エラーを発行します。

ただし、オブジェクトの作成を禁止するわけではありませんが、ポインター以外のインスタンスが宣言されたスコープの最後で破棄されるため、コンパイラーはエラーを発行し、インスタンスの作成を事実上禁止します。を使用してインスタンスを動的に割り当てることは引き続き可能ですが、インスタンスをnew削除できないため、メモリ リークが発生する可能性があることに注意してください。

于 2013-09-17T10:47:30.330 に答える
3

スタック上で FS_Only を宣言しようとすると

{ 
    FS_Only fs;
    //...
}

デストラクタは閉じ中括弧で自動的に呼び出されるため、コンパイル エラーが発生します。
もちろん、次のいずれかを実行deleteすることはできません。new

{ 
    FS_Only * fs = new FS_Only();
    //...
    delete fs; //also won't compile
}
于 2013-09-17T10:50:32.103 に答える
0

このようなオブジェクトを割り当てる唯一の方法は、割り当て解除を行わずに動的割り当てを使用することです (オブジェクトは、プログラムの実行中にリークされるか、ポインターによってアクセスされます。

静的インスタンスを割り当てようとすると、割り当てられたオブジェクトがスコープ外になるとコンパイル エラーが発生します (デストラクタ コードを呼び出すことができないため)。

于 2013-09-17T10:49:55.743 に答える