それD言語でできるよ!
って言いたかったので考えてみた.
より現実的な問題は,const_cast や mutable のような不穏なキーワードを伴わず,かつドキュメントと実際の動作が異なる場合です.
#include <iostream> class LargeObj; LargeObj* g_obj; class LargeObj { public: LargeObj() : id_(0) { g_obj = this; } void IAmNotEvil() const { g_obj->id_++; } int id_; }; void g(const LargeObj& obj){ obj.IAmNotEvil(); } void f(){ LargeObj tmp; std::cout << "id = " << tmp.id_ << std::endl; g(tmp); // tmp に対する変更はない std::cout << "id = " << tmp.id_ << std::endl; } int main() { f(); return 0; }C++ におけるコードレビューの重要性と活用 - NyaRuRuが地球にいたころ
ふむふむ.tmpに対する変更があるのにないと嘘をついている.これは困った.
でも・・・.
それD言語でできるよ!
IAmNotEvilメンバ関数とg関数にpure修飾子を追加します.
import std.stdio; LargeObj g_obj; class LargeObj { this() { g_obj = this; } void IAmNotEvil() const { g_obj.id_++; // 件の問題 } void IAmNotEvil2() const pure { // pureを追加 //g_obj.id_++; // ちゃんとコンパイルエラーになります } int id_; } void g(const LargeObj obj) { obj.IAmNotEvil(); } void g2(const LargeObj obj) pure { // pureを追加 obj.IAmNotEvil2(); } void f(){ LargeObj tmp = new LargeObj; writeln("id = ", tmp.id_); g(tmp); // tmp に対する変更はない(嘘) g2(tmp); // tmp に対する変更はない(本当) writeln("id = ", tmp.id_); } void main() { f(); }
g関数はtmp.id_を書き換えてしまっていますが,g2関数を経由して書き換えようとするとちゃんとコンパイルエラーになります.
めでたしめでたし.