閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

非ポインタ型の変数にポインタを代入

struct A
{
  A(A* = 0) {}

  void foo() {}
};

int main()
{
  A obj = new A();
  obj.foo();
  
  return 0;
}

上記のコードはコンパイルも実行も普通にできます。最初見たときはちょっとびっくりしましたが、普通にコンストラクタが呼ばれるんですね。当然、 new で確保した領域を解放していないので、このプログラムはメモリリークを起こします。

実際の例は CDialog クラスから派生したクラスでしたが、 VC のクラスウィザードで生成するダイアログクラスはコンストラクタの引数に CWnd* を取るので動いてしまったのでしょう。

こういった現象を起こさないようにするには、コンストラクタに explicit 指定子をつけます。

struct A
{
  explicit A(A* = 0) {}

  void foo() {}
};

int main()
{
  A obj = new A(); // error!
  obj.foo();
  
  return 0;
}

クラスウィザードで生成されるクラスのコンストラクタも自動的に explciit にしてくれてもいい気がしますね。