✏️

mutable修飾子の紹介

に公開

C++ にはconst correctnessという概念があります。
以下のように値が変わる事がない変数をconstにしたり、

const float pi_half (M_PI/2.0f);

以下のようにメンバー変数を変えないメンバー関数をconstにしたり、関数の中で変えない引数もconstにしたりすると、コードがより安全で分かりやすくなります。

class Scoreboard
{
public:
   Scoreboard() = default;
   
   float score (const int index) const; // メンバー変数を変更しないことを明示する
   float update (const int index, const float score); // メンバー変数を変更する

private:
   std::vector<float> m_scores;
};

float Scoreboard::score (const int index) const
{
   return m_scores.at (index);
}

float Scoreboard::update (const int index, const float score)
{
   return m_scores[index] = score;
}

でも以下のようにScoreboardをスレッドセーフにするためにstd::mutexを使う場合はどうでしょう?

class Scoreboard
{
public:
   Scoreboard() = default;
   
   float score (const int index) const;
   float update (const int index, const float score);

private:
   std::mutex m_mutex;
   std::vector<float> m_scores;
};

float Scoreboard::score (const int index) const
{
   std::lock_guard lock (m_mutex);  // コンパイルエラー
   return m_scores.at (index);
}

score()m_scoresを変えないのでconstにしたいところですが、std::lock_guardm_mutexを変更してしまうため、constにするとコンパイルエラーになります。

こういう場合のためにmutableというキーワードが存在します。
以下のようにm_mutexmutableにすれば、constメンバー関数の中でも変える事が出来るようになります。

class Scoreboard
{
public:
   Scoreboard() = default;
   
   float score (const int index) const;
   float update (const int index, const float score);

private:
   mutable std::mutex m_mutex;  // !! mutable
   std::vector<float> m_scores;
};

float Scoreboard::score (const int index) const
{
   std::lock_guard lock (m_mutex);  // m_mutexを変更してもいい
   return m_scores.at (index);
}

でも普通のメンバー変数をmutableにしてしまうと、関数にconstを付ける意味がなくなってしまうため、本記事みたいなmutex型のメンバー変数が唯一のユースケースだと思った方がいいですね。


|cpp記事一覧へのリンク|

Discussion