result_t work(resource_t& resource) {
lock_t ___(resource);
return work_impl(resource);
}
返された後にデストラクタ___
が呼び出されることが保証されていますか? または、コンパイラは呼び出す前にwork_impl()
自由に破棄できますか?___
work_impl()
result_t work(resource_t& resource) {
lock_t ___(resource);
return work_impl(resource);
}
返された後にデストラクタ___
が呼び出されることが保証されていますか? または、コンパイラは呼び出す前にwork_impl()
自由に破棄できますか?___
work_impl()
式work_impl(resource)
が実行され、結果が呼び出し側にコピーされるか、一時的に使用されます。その後、オブジェクト___
は破棄されます。
一方、__
または___
を識別子の接頭辞として使用しないでください。それらはコンパイラ用に予約されています。
デストラクタが自明でない場合、コードの残りの部分が正しい場合、時期尚早に呼び出されることはありません。もちろん、未定義の動作 (たとえば、2 つ以上の隣接する変数名_
) の場合、保証はありません。
このプログラムの動作は実際にはundefinedであり、識別子 __
は予約されており、ドラフト C++ 標準17.6.4.3
予約名からわかるように、パラグラフ2は次のように述べています。
この句で明示的に許可されている場合を除き、プログラムが予約されているコンテキストで名前を宣言または定義する場合、その動作は未定義です。
17.6.4.3.2
そして、グローバル名のセクションをさらに見てみると、次のように書かれています。
2 つのアンダースコア _ _ を含む名前、またはアンダースコアで始まり、その後に大文字が続く名前 (2.12) は、実装で使用するために予約されています。
そのため、コンパイラー__
がユーザーコードで自由に使用できることを文書化していない限り、それは予約されています。
デストラクタは暗黙的に呼び出されます
したがって、このプログラムが未定義の動作を呼び出さなかった場合、暗黙的に呼び出されるデストラクタのルールは、ドラフト標準セクション12.4
Destructotrsパラグラフ11から取得できます(強調鉱山)
— プログラムの終了時 (3.6.3) に静的な保存期間 (3.7.1) を持つ構築されたオブジェクトの場合、
— スレッド終了時にスレッド保存期間 (3.7.2) を持つ構築されたオブジェクトの場合、
—オブジェクトが作成されたブロックが終了するとき (6.7)、自動保存期間 (3.7.3) を持つ構築されたオブジェクトの場合、
— 一時オブジェクトの有効期間が終了したときに構築された一時オブジェクトの場合 (12.2)、
つまり、終了時に自動オブジェクトのデストラクタが呼び出されますwork()
。これは、結果が返された後に発生する必要があります。さらに、オブジェクトが破棄される順序も6.6
Jump ステートメントで指定されていることがわかります。
スコープから出ると (どのように達成されても)、そのスコープで構築された自動保存期間 (3.7.3) を持つオブジェクトは、それらの構築の逆の順序で破棄されます。[ 注: 一時的なものについては、12.2 を参照してください。—終わりのメモ]
2 つのアンダースコアを含む名前__
、またはアンダースコアの後に大文字が続く名前は、どのスコープでも予約されていることに注意してください。
違いを見分ける方法がない場合、コンパイラは好きなことを自由に行うことができます。しかし、デストラクタがプログラムから見える効果を持っている場合、それは常にwork_impl
戻り後に発生します。