https://en.cppreference.com/w/cpp/language/lifetime inNotesセクションにはこのコードがあり、再現ここに:
struct A {
int* p;
~A() { std::cout << *p; } // if n outlives a, prints 123
};
void f() {
A a;
int n = 123; // if n does not outlive a, this is optimized out (dead store)
a.p = &n;
}
このNotesセクションで何を言おうとしているのですか?
n
がa
より長生きしないことは明らかなので、私が理解したことから、コードはUB(またはそれ)です。
それはどういう意味ですか:
非クラスオブジェクト(保存期間の終了)とクラスオブジェクト(構築の逆順)の間のライフタイム終了ルールの違いが重要
しかし、それは問題とは言いませんhow。
このセクション全体で非常に混乱しています。
これは、C++のライフタイムルールの奇妙な側面です。 [basic.life]/1が教えてくれます オブジェクトのライフタイムが終了すること:
T
が非自明なデストラクタ([class.dtor])を持つクラス型の場合、デストラクタ呼び出しが開始されます。または- オブジェクトが占有しているストレージが解放されるか、o([intro.object])内にネストされていないオブジェクトによって再利用されます。
強調が追加されました。 int
は「非自明なデストラクタを持つクラスタイプ」ではないため、そのライフタイムは、占有しているストレージが解放されたときにのみ終了します。対照的に、A
は重要なデストラクタを持つクラス型であるため、デストラクタが呼び出されるとその存続期間は終了します。
[basic.stc.auto]/1 に従って、スコープが終了すると、スコープのストレージが解放されます。
[自動保存期間を持つ変数]の保存は、作成されたブロックが終了するまで続きます。
ただし、自動変数は [stmt.jump]/2 に従って破棄されます。
スコープからの終了時(ただし、達成された場合)、そのスコープで構築された自動ストレージ期間を持つオブジェクトは、構築の逆の順序で破棄されます。
破棄の順序は指定されていますが、自動ストレージ解放の順序はnotが指定されていることに注意してください。これは、各変数が破棄された直後に実装がストレージを解放したり、後で一度にすべてを解放したり、任意の他の順序でストレージを解放したりできることを意味します。
現在、各変数について個別に話すのではなく、ストレージに単数形を使用する(「...のストレージ」)という事実は、そのスコープでストレージ全体を一度に解放する意図があることを示唆している可能性があります。しかし、標準にはこれに関する明示的な記述はありません。そのため、ストレージが解放される前に変数が破棄される限り、破棄と解放の順序はすべて正当であるように見えます。
これは、n
がa
より長く存続するために、コードが完全に機能することを意味します。ただし、が機能するか動作するかは不明です。
この例は Core Language Issue 2256 から引用されています:
セクション:6.8 [basic.life]ステータス:製図送信者:リチャード・スミス日付:2016-03-30
6.4 [basic.lookup] bullet 1.4によれば、
n
のライフタイムはストレージが解放されるまで(つまり、a
のデストラクタが実行された後)延長されるため、次の例は動作を定義しています。void f() { struct A { int *p; ~A() { *p = 0; } } a; int n; a.p = &n; }
オブジェクトに重要なデストラクタがあるかどうかに関係なく、すべてのオブジェクトの存続期間の終わりが同じように扱われると、より一貫したものになります。
2018年3月の会議からのメモ:
CWGは提案された方向に同意しました。
重要な考え方は、オブジェクトの寿命がその破壊で終了するか、メモリが解放される時点でプログラムのセマンティックに影響を与えるかどうかです。例では、
n
のライフタイムがn
の破壊で終了する場合、プログラムは未定義です。
メモリが解放されるまでn
のライフタイムが終了する場合、プログラムは動作を定義しています1。
したがって、オブジェクトのライフタイムがいつ終了するかを判断するには、さらに議論する必要があります。
1 これは、 Core Language Issue 2115 :
セクション:9.6 [stmt.jump]ステータス:製図送信者:リチャード・スミス日付:2015-04-16
ブロックの終了時の自動変数の破棄と変数のストレージの解放との間の相対的な順序は、標準では指定されていません。すべてのデストラクタが最初に実行され、次にストレージが解放されますか、またはインターリーブされますか?
2016年2月の会議からのメモ:
CWGは、すべての破棄が完了するまでストレージを保持することに同意しましたが、「as-if」ルールではこの順序の観察不可能な最適化が許可されます。
意図は、すべての破棄が完了した後に自動変数のメモリ解放が発生することです。