✏️
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_guard
がm_mutex
を変更してしまうため、const
にするとコンパイルエラーになります。
こういう場合のためにmutable
というキーワードが存在します。
以下のようにm_mutex
をmutable
にすれば、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
型のメンバー変数が唯一のユースケースだと思った方がいいですね。
Discussion