7

この質問に答えた後、標準論文で満足のいく答えが見つからなかったので、疑問に思い始めました。標準では、言及された変数の初期化について次のように述べています。

§6.7 [stmt.dcl] p4

[...] それ以外の場合、そのような変数は、コントロールがその宣言を最初に通過するときに初期化されます。このような変数は、初期化の完了時に初期化されたと見なされます。例外をスローして初期化が終了した場合、初期化は完了していないため、次に制御が宣言に入ったときに再試行されます。

例外をスローする以外の理由で初期化が失敗した場合に、初期化が再試行される原因については言及されていません (longjmp()いくつか例を挙げると、 、thead exit、シグナル)。

標準の何かを見落としていませんか? 初期化、宣言、および例外句を何度も調べ、 「静的」をすばやく検索してCWG 欠陥の目次を調べましたが、関連するものは見つかりませんでした。

これは規格の過少仕様 (およびそのような欠陥) ですか?

4

2 に答える 2

2

C++ 仕様は、C++ 仕様に含まれるもののみを定義できます。注意: C++ 仕様は、それが定義する仮想マシンの動作を定義します。そして、何かが起こり得ることを定義していない場合、それが起こり得るとは言っていない何かについての C++ の動作を定義していないことは確かです。

C++ 仕様によると、スレッドは正確に 3 つの方法で終了できます。つまり、メイン関数から戻る、メイン関数を介して例外をスローする、プロセスを直接終了する (std::terminateまたは同様の関数と同様)。つまり、C++ スレッドは他の方法で終了することはできません。ExitThread標準 C++ には関数はありません。同様に、std::thread外部または内部でスレッドを強制終了することはできません。

したがって、C++ が発生しないと言うこのことを引き起こすものはすべて、定義上未定義です。「未定義の動作」でさえないと思います。C++ 11 が実際にスレッドの相互作用がどのように機能するかを規定する前に、スレッド化があったのはそのあいまいな空間でした。

同じことが「シグナル」にも当てはまります。C++ 仕様では、これらが関数を終了させる可能性があるとは述べていません。ここにドラゴンがいます。

に関してはlongjmp、それは の動作によってカバーされlongjmpます。を使用して関数を終了すると、 と を使用しlongjmpた場合と同様に、その関数は終了しません。また、C++ では、コンストラクターが完了したときにのみオブジェクトが構築されます。したがって、オブジェクトの初期化は完了せず、初期化されていません。throwcatch

私は ISO C 仕様 (C++ が の動作を参照している) を持っていませんが、 C++11 では、未定義の動作が発生する限り、/を/とlongjmp同一視できることを強く推奨しています。throwcatchlongjmpsetjmp

§18.10 [support.runtime] p4:

この国際標準では、関数シグネチャ longjmp(jmp_buf jbuf, int val) の動作がより制限されています。setjmp/longjmp 呼び出しペアは、setjmp と longjmp を catch と throw で置き換えると、任意の自動オブジェクトに対して重要なデストラクタが呼び出される場合、未定義の動作になります。

だから私はこれが過小評価されているとは思わない。きれいに整頓されていないかもしれませんが、すべてのピースがそこにあります。

于 2012-01-30T03:29:31.877 に答える
0

テキストが 1 つの特定のケースに言及しているからといって、省略しても他のケースが異なることを意味するものではありません。初期化が完了しないようにする他の方法がある場合、実装は次の実行で再試行する必要があります。

ニコルの答えはほとんど正しいと思いますが、自明でないコンストラクターは自明でないデストラクタを意味するものではありません。longjmpしたがって、初期化を中断して再試行する必要がある場合があります。これは、最初に初期化を実行しようとするスレッド間の競合状態を防ぐためにミューテックスが必要なマルチスレッド環境でのみ注意が必要です。ファントム ミューテックス オブジェクトは、初期化されたオブジェクトに自明でないデストラクタがない場合でも、重要なデストラクタが必要です。考えられる結果は、デッドロックです。これはおそらく DR に適した資料です。

于 2012-01-30T16:13:07.047 に答える