4

私はscoped_lockがどのように機能するかについて非常に興奮しており、特定の実行コードのタイミングに関して同様の実装を行うことができるかどうか疑問に思っていました

構築時にタイマーを開始し、削除時にタイマーを停止して経過時間を報告する単純なクラス scoped_timer を実装するとしたら、このサンプル コードは正しく時間を計ることができますか?

func()
{
    //some code
    {
       scoped_timer a;
       //some code that does not include a
     }
     //some code
 }

scoped_time a実際には、最初に構築され、範囲外になったときに正確に破棄されることが保証されています。コンパイラは、コードに依存しないため、スコープの最後で正確に破棄したり、最初に構築したりしないようにコードを並べ替えることができますobject aか? C++ 標準からの保証はありますか?

ありがとう

ダニエル

4

1 に答える 1

5

コードは、希望どおりに動作することが保証されています。

この保証は C++ では重要です。C++ は関数型プログラミング言語ではないため、C++ のほぼすべての関数が (現在のスレッドの実行フローから、または他のスレッドや他のプロセスからの) 副作用を持つ可能性があるためです。 、データが として宣言されているかどうかに関係なくvolatile)。このため、言語仕様では、完全な式の順序付けが保証されています。

これを C++11 標準からまとめるには、まとめて考慮する必要がある節がいくつかあります。

最も重要な条項は §1.9 です。

§1.9プログラムの実行 [intro.execution]

1 この国際規格のセマンティック記述は、パラメータ化された非決定論的抽象マシンを定義します。この国際規格は、適合する実装の構造に要件を課していません。特に、抽象マシンの構造をコピーまたはエミュレートする必要はありません。むしろ、以下で説明するように、抽象マシンの観察可能な動作をエミュレートする (のみ) ために、適合する実装が必要です。* (<-- 脚注は標準自体にあります)

* この規定は「as-if」ルールと呼ばれることもあります。これは、観察可能なデータから判断できる限り、結果があたかも要件に従っているかのようである限り、実装はこの国際標準の要件を自由に無視できるためです。プログラムの振る舞い。たとえば、実際の実装では、式の値が使用されておらず、プログラムの観察可能な動作に影響を与える副作用がないと推定できる場合、式の一部を評価する必要はありません。

(本文の太字は私です。)

この条項は、この質問に関連する 2 つの重要な要件を課しています。

  1. 式に副作用がある場合は、評価されます。あなたの場合、式scoped_timer a;には副作用がある可能性があるため、評価されます。

  2. ...準拠する実装は、以下で説明するように、抽象マシンの観察可能な動作を (のみ) エミュレートする必要があります。」、ここで、「以下」には同じセクションの条項 13 および 14 が含まれます。

§1.9.13 Sequenced before は、単一のスレッド (1.10) によって実行される評価間の非対称で推移的なペアワイズ関係であり、これらの評価の間に半順序を誘導します。任意の 2 つの評価 A と B が与えられた場合、A が B の前に配列されている場合、A の実行は B の実行よりも優先されます。A が B の前に配列されておらず、B が A の前に配列されていない場合、A と B は配列されていません。[ 注: 順序付けされていない評価の実行はオーバーラップする可能性があります。—終わりの注 ] 評価 A と B は、A が B の前にシーケンスされるか、B が A の前にシーケンスされる場合、不定にシーケンスされますが、どちらが指定されていません。[ 注: 不定の順序で評価を重ねることはできませんが、どちらかを最初に実行することはできます。—終わりのメモ]

§1.9.14完全式に関連付けられたすべての値計算と副作用は、次に評価される完全式に関連付けられたすべての値計算と副作用の前に並べられます。* (<-- ここの脚注は関係ありません)

したがって、式scoped_timer a;(完全な式) には副作用があり、評価される可能性があります。そのため、 の値の計算はa、ブロック内の次のステートメントの前に並べられます。

オブジェクトの破壊に関してはa、それはより簡単です。

§3.7.3.3自動保存期間を持つ変数に初期化または副作用のあるデストラクタがある場合、そのブロックの終了前に破棄してはならず、未使用のように見えても最適化として削除してはなりません。クラス オブジェクトまたはそのコピー/移動は、12.8 で指定されているように削除できます。

これにより、ブロックが終了するまでデストラクタが呼び出されないことが明確になります。

補遺そして、すべてのブロック レベルの変数ブロック スコープの最後で破棄されている (およびそのデストラクタが呼び出されている) ことを確認するために、C++11 標準を以下に示します。

§3.7.3.1 registerを明示的に宣言したブロックスコープ変数、または static または extern を明示的に宣言しなかったブロックスコープ変数には、自動ストレージ期間があります。これらのエンティティのストレージは、エンティティが作成されたブロックが終了するまで続きます。

§3.7.3.2 [ 注: これらの変数は、6.7 で説明されているように初期化および破棄されます。—終わりのメモ]

...および上記の§6.7:

§6.7.2自動保存期間 (3.7.3) を持つ変数は、それらの宣言ステートメントが実行されるたびに初期化されます。ブロックで宣言された自動保存期間を持つ変数は、ブロックの終了時に破棄されます (6.6)。

ブロックは、次の中括弧のペアの間のすべてのコードとして定義され{}ます。

§6.3.1複数のステートメントを必要な場所で使用できるように、複合ステートメント (「ブロック」とも呼ばれます) が提供されます。

compound-statement:

    { statement-seq }

statement-seq:

    statement

    statement-seq statement

複合ステートメントは、ブロック スコープ (3.3) を定義します。

注: compount-statement(etc) セクションは慣れるまでに時間がかかりますが、重要な点は、ここで開き中括弧{と閉じ中括弧}は、実際にはコード内の文字通りの開き中括弧と閉じ中括弧を意味するということです。blockこれは、スコープが中括弧の間の一連のステートメントとして定義されている C++11 標準の正確な場所です。

ピースをまとめる: 上記で引用したように、標準ではThe storage for these entities lasts until the block in which they are created exitsと が述べられているため、質問Variables with automatic storage duration declared in the block are destroyed on exit from the blockのオブジェクトa(および任意のブロックレベル オブジェクト) がブロックの最後まで存続し、破棄されて、ブロックの終了時に呼び出されるデストラクタ。

于 2013-04-03T05:35:51.543 に答える