ゆとりーなの日記

日記的な事を書いて行くと思はれる

volatileの綴りが安定しない

秋刀魚ってホントに飛びやすいですね。一応言っておきますが、麻雀です。

volatile纏め(道半ば)

C++界隈でも割と謎なvolatileについて纏めておきます。正直私もまだよく分かっていません。

volatile変数ってなんぞ

取り敢えず宣言はこうです。

volatile int value;

型の前にくっつけます。constとかと構文は殆ど変わらないので型名の後でもいいと思います。多分。
意味はコンパイラの最適化を抑制するってやつですね。何に使うかというとまあスレッドの無限ループを抜ける条件変数とかですね。

bool flag(false);

int main() {
  スレッド起動;
  flag = true; // ここでスレッドを抜ける?
  return 0;
}

// スレッドの中身
for (;;) {
  if (flag) break;
  // 処理
}

flagにvolatileが付いていませんが、これだとスレッドが無限ループを抜けない可能性があるんです。コンパイラが気を利かせてスレッド内ではflagを調べるときに一々メモリアクセスしないようにしたり、はては条件文を引っこ抜いたりする可能性があるんですね。
ここで

bool flag(false);

としておけばコンパイラは空気を呼んで変な最適化はしなくなるんですね。
この手の使い方が有名なことから、派生してvolatile変数はマルチスレッドで同時に読み書きされない変数として使うという黒魔術が流行っているみたいですが、私の記憶では同時に読み書きされないという保証はなかったはずです。一部環境ではあった気もするので厄介です。因みにvolatile変数はconst_castでvolatileが取れます。

volatileメンバ関数ってなんぞ

これが謎だったんですね。因みに構文上はconstメンバ関数と変わりません。

class Toki {
public:
  int fp() volatile {
    return hp_;
  }
private:
  int hp_;
};

で、意味は正直見当つきません。constメンバ関数の場合は、このメソッドではオブジェクトは変更してませんよという宣言であるわけですが(厳密には違う場合もあるが)、volatileはこのメソッドではオブジェクトの最適化をしてませんという宣言になるのかと考えると意味分かりません。
で、参考になるページを見つけました。発掘 volatile メンバ関数 - Natural Softwareを見て得た私の結論です。volatileメンバ関数はconstメンバ関数の様に意味を考えてはいけなかったんです。
例えば次のコードを見てみましょう。

class Toki {
public:
  int hp() {
    return hp_;
  }
private:
  int hp_;
};

int main() {
  volatile Toki toki;
  int hp(toki.hp()); // コンパイルエラー
  return 0;
}

何を血迷ったかトキの最適化を阻止すべくvolatileを付けたところ華麗にコンパイルエラーが起こります。このエラーを阻止するためには、

class Toki {
public:
  int hp() volatile {
    return hp_;
  }
private:
  int hp_;
};

とすればいいんです。多分これがvolatileメンバ関数の使い道です。
ほんとはもっと深い意味があるのかもしれませんが、現状の私にはこれ以上の事は分かりません。constメンバ関数内ではメンバ変数の値が書き換えられないといった制約がありますが、volatileメンバ関数のにはどんな制約があるのかもよく分かっていません。