✏️
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