2007年09月24日

const修飾子と定数及びポインタ

Effective C++を読んでのメモ

C言語では書き換え不可という意味であったconstであるが、C++では定数として利用できるconst。それによりC++では配列の添え字として変数の利用が可能である。ここで注意したいのはC++では#defineで指定したマクロ名を定数として利用するのは好ましくない。その理由として、まず大抵のコンパイラの実装はプリプロセッサ命令として#defineで指定されたマクロ名の置き換え処理を行うので、マクロ名は隠蔽される。もしその定数が原因でコンパイルエラーが起きた際に、原因の特定が厄介になってしまうのである。またスコープの概念も#defineには適用されないのでクラスの中で定数を宣言したい場合には#defineでは無く、constを使うべきである。

ところでconst修飾子とポインタの関係について。

int num = 100;

const int *cVar1 = #  //データに対しconst (1)
int const *cVar2 = #  //データに対しconst (2)
int *const cVar3 = #  //ポインタに対しconst (3)
const int *const cVar4 = #  //ポインタとデータに対しconst (4)
int const *const cVar5 = #  //ポインタとデータに対しconst (5)

所持している参考書では(1)と(3)と(4)のスタイルが紹介されていたが、(1)に関しては(2)の形でも表すことが可能である。(2)により(4)に関しては(5)のようなスタイルも可能である。コーディングスタイルを規定する時のために頭の隅に入れておきたい。


2007年09月22日

新カテゴリ追加

カテゴリとして「テクニカルレビュー」と「電子回路」を新設。

テクニカルレビューは主に技術的なWeb情報に関してのコメントなど。
電子回路は回路の設計や製作、マイコンに関する技術メモなど。
posted by vNull | Comment(1) | TrackBack(0) | 更新情報 | Edit

2007年09月19日

仮想デストラクタの持つ意味

以下のコードは危険である。

#include<iostream>
using namespace std;

class Base{
  public:
  Base(){cout << "Base::Constructor" << endl;}
  ~Base(){cout << "Base::Destructor" << endl;}
};

class Derived:public Base{
  public:
  Derived(){cout << "Derived::Constructor" << endl;}
  ~Derived(){cout << "Derived::Destructor" << endl;}
};

int main(void)
{
  Base *p = new Derived();
  delete p;
}

実行結果

Base::Constructor
Derived::Constructor
Base::Destructor

基底クラスのオブジェクトとして派生クラスのオブジェクトを生成し代入しているが、delete時に派生クラスのオブジェクトのデストラクタの呼び出しが行われないのである。仮に派生クラスのメンバ変数にポインタ等が含まれており、デストラクタでそのポインタのメモリを開放する記述を行っていた場合、デストラクタが呼び出されずにメモリリークの原因となってしまう。その為、継承の可能性のあるクラス(事実上ほぼ全て)のデストラクタは仮想デストラクタにしておく必要がある。そうすることによって、派生クラスのデストラクタが呼び出され、さらに基底クラスのデストラクタの呼び出しも正常に行われるのである。

#include<iostream>
using namespace std;

class Base{
  public:
  Base(){cout << "Base::Constructor" << endl;}
  virtual ~Base(){cout << "Base::Destructor" << endl;}
};

class Derived:public Base{
  public:
  Derived(){cout << "Derived::Constructor" << endl;}
  virtual ~Derived(){cout << "Derived::Destructor" << endl;}
};

int main(void)
{
  Base *p = new Derived();
  delete p;
}

実行結果

Base::Constructor
Derived::Constructor
Derived::Destructor
Base::Destructor

ちなみに「デストラクタは仮想デストラクタにしておく必要がある」とあるが、逆に継承を望んでいるクラスのデストラクタが仮想デストラクタで無い場合は、そのクラスが継承を想定していない(継承に対しての対策が無い)設計だという可能性も考える必要がある。
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。