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(0) | 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

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

NVIイディオムとは

Effective C++を読んでのメモ

NVI(non virtual interface:非仮想インターフェース)イディオムとはデザインパターンのテンプレートメソッドの具体化の一例。クラスに実装したpublicな関数(非仮想関数)からprivateな仮想関数を呼び出す設計。publicな関数がラッパ関数(Wrapper Function)となり、派生クラスで再定義された仮想関数を呼び出す仕組み。派生クラスで不変的な動作を基底クラスのpublicな関数で定義したい場合などに有効。

2007年09月13日

関数のインライン展開について

Effective C++を読んでのメモ

関数名の前にinlineキーワードをつけると、コンパイラ側の方で可能なら関数のインライン展開を行ってくれる関数定義の機能。もともとはC++における新機能であったが、C99によりC言語でも可能となった。たいていのコンパイラの実装では、関数内にforやwhileなどのループ文や再帰などの記述が含まれている場合、あるいはその関数のアドレスを関数ポインタ等を用いて呼び出している場合にインライン展開行わない。そのほか、クラス定義の中に書かれたコンストラクタやデストラクタは通常は非明示的にインライン関数とされる。しかしコンストラクタやデストラクタでループなどを用いていなくてもインライン展開されない可能性がある。その一つとしてコンパイラ側がコンストラクタ及びデストラクタの呼び出しに関数ポインタを用いる場合があるからだ。
なのでインライン展開を望む関数に対しinlineキーワードを用いる場合はその性質に注意する必要がある。

2007年09月11日

関数の引数について

Effective C++を読んでのメモ

C言語の仕様では関数の引数の評価順番は定められていない。C++でも同様なので、newで確保したオブジェクトに対してにスマートポインタを用いる際、後から評価された引数から例外が投入される可能性のある場合、メモリリークの原因となる。よってそれを防ぐためにはnewで確保する記述は独立した形が好ましい。

2007年09月07日

いま話題のワンセグ、LDT-1S301Uについて

ldt1s301u.gif
メーカーHPへ
今、携帯をはじめパソコン用のPCカードタイプやUSBタイプ、カーナビなど様々な
種類のあるワンセグチューナー。
今回購入したのはLogitecのLDT-1S301Uという製品。アンテナを二本搭載している
のが特徴。

まぁ映ればいいなぁ程度で買ってみたものの、結果として案の定映らなかった。
原因ははっきりしていて自宅が鉄骨であること。ノートパソコンにチューナーを
つないで家の外に出てみると受信感度100%で色々な番組を見ることが出来た。
でも外に出ないと見れないようじゃパソコンで見る必要も無い。そういう点では
やはりワンセグ搭載の携帯電話とは比べ物にならないな。他社のワンセグ
チューナーのオプションパーツとしてF型ケーブルに変換できるキットもある
ようだが、この製品にそのようなオプションは無い。アンテナの取り外しが可能
なので自作という手もあるが・・

まぁ外出時にこれから役に立つ日が来るだろう。
例のごとくノートPC小道具として収納。

2007年09月02日

PTM-UBTSETについてアレコレ

main_photo1.jpg
メーカーHPへ

Skypeを使って知り合いなどと電話することが多く、結構夜遅くまで話すこともしばし。
寝転がりながら話をする場合に、有線のヘッドセットでは、結構コードが邪魔になる。
そこでBluetoothによる無線のヘッドセットを、秋葉原に行ったときに買ってきた。
値段は4980円。この値段の内訳は、Bluetoothアダプタが高いのではなく、どうもヘッドセットの本体のようだ。
メーカーを問わないならBluetoothのアダプタ自体は1000円程度で手に入る。

使ってみて思ったことがいくつか。
●とりあえず無線なので非常に快適
●そこそこ遠くまで電波が届く。自宅は2DKの軽量鉄骨造り。
寝室にパソコンを置き、台所へお茶をとりに行く程度なら問題なし。
●無線LANとの電波干渉あり。
ノートPCではPCカードタイプの無線LANアダプタを使っているが、直ぐ近くの
USBポートにBluetoothアダプタを挿して使ったところ、激しくノイズがのった。
●ヘッドセット側を充電する必要があるのが不便。
連続通話時間は2時間らしいので、通話中に充電が切れることがしばし。

んで話し相手に、無線のヘッドセットにしてからノイズ音が酷くなったといわれたのがちょっとショック。
・・まぁどうやら有線のほうが聞く側に優しそう。ノートPC小道具としてしまっておくか。

DirectX 9: デバイスがロストした時の復旧方法

DirectX 9にで、フルスクリーンからウィンドウへ戻ったときや、非アクティブ状態から復帰した場合に、デバイスの再構築が必要となる。

DirectX 8にて解説を行っているサイトでは、単純にReset()を呼べば良いと書かれているが、どうも上手くいかないので色々調べてみたところ、どうやら「ロストしたデバイスをリセットできない状態」というタイミングが存在するらしく、適切な関数でリセットできる状態かどうかを調べる必要があるらしい。以下にその手順を示す

if(DeviceLost){
  if(FAILED(hr = pDevice->TestCooperativeLevel())){
    if(hr == D3DERR_DEVICENOTRESET){
      //デバイスのリセットを行う処理を書く。具体的には
      //pDevice->Reset(&d3dpp)
      //を呼び出してリセットを行うが、当然d3dppはDirect3Dを
      //初期化するときに記述した形でもう一度記述を行う。
    }
  }else{
    DeviceLost  = false;
  }
}else{
  if(FAILED(pDevice->Present( NULL, NULL, NULL, NULL ))){
    DeviceLost  = true;
  }
}

まず、ロストするとPresent()が失敗するので、それをチェックする。次にTestCooperativeLevel()でデバイスをリセットできるかどうか確認を行う。もしTestCooperativeLevel()の戻り値がD3DERR_DEVICENOTRESETであれば、ロストしたデバイスの復旧が可能となり、Reset()が可能となる。

2007年09月01日

STL setのテンプレート引数にクラスを用いた実装例

#include <iostream>
#include <set>

#include <cstdlib>
#include <ctime>
using namespace std;

class Data{
public:
  int ID;
  int Score;
  Data(int ID,int Score):ID(ID),Score(Score){};

  bool operator<(const Data &d) const{
    return Score<d.Score;
  }
};

int main(void)
{
  multiset<Data> User;

  srand((unsigned)time(NULL));

  for(int i=0;i<20;i++)
    User.insert(Data(i,rand()%1000));

  for(multiset<Data>::iterator itr=User.begin();itr!=User.end();++itr)
    cout << (*itr).ID << "," << (*itr).Score << endl;
  return 0;
}