C ++での揮発性と可変性


85

揮発性と可変性の違いについて質問があります。私は、2つの両方がそれが変更される可能性があることを意味することに気づきました。ほかに何か?それらは同じものですか?違いは何ですか?それらはどこに適用できますか?なぜ2つのアイデアが提案されているのですか?それらを別の方法で使用する方法は?

どうもありがとう。

回答:


112

mutableフィールドもを通じてアクセスされたオブジェクトに変更することができるconstポインタまたは参照、またはでconstコンパイラは、R / Oメモリにそれを隠ししない知っているので、オブジェクト。volatile場所は、コンパイラが最適化などに値が「多分持つことができないという不正な仮定の下で、その値の割り当てを登録していない知っているので、コンパイラは(例えば、いくつかのカーネルレベルのドライバ)について知らないコードによって変更することができるものですそのレジスタに最後にロードされてから「変更されました」。非常に異なる種類の無効な最適化を停止するために、非常に異なる種類の情報がコンパイラーに提供されます。


13
volatileオブジェクトは、CPUをまったく含まないプロセスによっても変更される可能性があります。たとえば、通信ペリフェラルのバイト受信レジスタは、バイトの受信時にそれ自体をインクリメントできます(これにより、割り込みがトリガーされることもあります)。もう1つの例は、ペリフェラルの保留中の割り込みフラグレジスタです。
Mike DeSimone 2010年

55
また、volatileオブジェクトがコンパイラの知識の範囲外で変更される可能性があることを意味するだけでなく、オブジェクトへの書き込みが役に立たないように見えても、コンパイラがオブジェクトへの書き込みを排除できないことも意味します。たとえば、次のx = 1; x = 0; 場合にx揮発性であり、コンパイラは、(ハードウェアレベルで有意であるかもしれない)の両方の書き込み操作を放出しなければなりません。ただし、非揮発性オブジェクトの場合、コンパイラは1使用されないため、書き込みに煩わされないことを選択できます。
Michael Burr 2010年

15
オブジェクトは、両方のマークを付けることができconst、およびvolatile!オブジェクトを変更することはできませんが、背後で変更することはできます。
CTMacUser 2013年

2
@Destructor:通常の状況は、ハードウェアデバイスレジスタへの書き込みです。
Michael Burr 2016年

5
@Destructorは、LEDのステータスを制御しているとしましょう。書き込み0はオフになり、書き込み1はオンになります。エラーステータスを伝えるためにLEDを点滅させる必要があるが、コンパイラが最後の書き込みを除くすべての書き込みを最適化することを決定した場合、値が使用されていないため、LEDが点滅せず、希望する動作が実現されません。 。
iheanyi 2017年

28

mutable:mutableキーワードは、それを囲むconstステートメントをオーバーライドします。constオブジェクトの可変メンバーは変更できます。

volatile:volatileキーワードは、実装に依存する修飾子であり、変数を宣言するときに使用されます。これにより、コンパイラーはこれらの変数を最適化できなくなります。Volatileは、コンパイラが実行する可能性のある最適化と競合する可能性のある、予期しない方法で(つまり、割り込みによって)値が変更される可能性のある変数とともに使用する必要があります。

ソース


あなたが言ったVolatile should be used with variables whose value can change in unexpected ways、我々はランダムでそれを使用することを好むでしょうか?
Asif Mushtaq 2015年

@AsifMushtaqは値ではありません。方法。可変は、あなたが書いたコードが持つ許可に影響を与えます。したがって、constptrまたはconst参照を介して変数にアクセスできます。あなたのコードがそれを変更していない場合はどうなりますか?コンパイラがptrまたは参照型をチェックできないものはありますか?それは不安定です。また、volatileは、キャッシュをメインメモリに強制的に書き戻します。したがって、これはマルチスレッドコードでLOTを使用します。:)
ダン

22

それらは間違いなく同じものではありません。ミュータブルはconstと相互作用します。constポインターがある場合、通常はメンバーを変更できません。ミュータブルはそのルールに例外を提供します。

一方、揮発性は、プログラムによって行われた変更とはまったく関係がありません。これは、コンパイラの制御が及ばない理由でメモリが変更される可能性があることを意味します。したがって、コンパイラは毎回メモリアドレスを読み書きする必要があり、コンテンツをレジスタにキャッシュできません。


「一方、揮発性は、プログラムによって行われた変更とはまったく関係ありません...」 -うーん、メンバーを揮発性にして、コンパイル中に何が壊れるかを確認します。事後にvolatileを追加しようとするのは、事後にconstを追加しようとするのとよく似ています...痛いです。
jww 2015年

@jww:プログラムによる書き込みとはまったく関係ありません。タイプのオブジェクトのアドレスを取得してT、に格納し、const T*そこから読み取ることができます。そのオブジェクトを作成すると、書き込みを試みたことがなくても、volatileそのアドレスをに格納するconst T*ことは失敗します。 volatileプログラムコードからの変更/修正/メモリ書き込みは完全に直交しています。
Ben Voigt 2015年

17

違いについての大まかな、しかし効果的な考え方は次のとおりです。

  • コンパイラは、可変オブジェクトがいつ変更されるかを認識しています。
  • コンパイラは、揮発性オブジェクトがいつ変更されるかを知ることができません。

1
その意味で:volatilebytes_received、mutablereference_count。
Mike DeSimone 2010年

11

マークされた変数をmutable使用すると、宣言されたメソッドで変数を変更できますconst

マークされた変数はvolatile、コードが指示するたびに変数の読み取り/書き込みを行う必要があることをコンパイラーに通知します(つまり、変数へのアクセスを最適化することはできません)。


4

volatileは、マルチスレッドアプリケーションを処理するときにも非常に役立つことを付け加えておきます。つまり、メインスレッド(main()が存在する場所)があり、変数「app_running」がtrueの間回転し続けるワーカースレッドを生成します。main()は、「app_running」がtrueかfalseかを制御するため、「app_running」の宣言にvolatile属性を追加しない場合、コンパイラがセカンダリスレッドによって実行されるコードで「app_running」へのアクセスを最適化すると、main( )「app_running」をfalseに変更する可能性がありますが、値がキャッシュされているため、セカンダリスレッドは実行を継続します。LinuxとVisualC ++でgccを使用しても同じ動作が見られます。「app_running」宣言に入れられた「volatile」属性が問題を解決しました。そう、


1
番号!これはよくある誤解です。C ++ 11とC11は、この目的のためにアトミックを導入しましたstackoverflow.com/questions/8819095/…–
KristianR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.