...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

Re: C++ におけるコードレビューの重要性と活用

それ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関数を経由して書き換えようとするとちゃんとコンパイルエラーになります.
めでたしめでたし.

余談

pureメンバ関数のpure性が保証される範囲って,constメンバ関数と同じインスタンススコープなんですね.
pure非メンバ関数と同じなのかと思っていました.