MASATOの開発日記


前の開発日記 次の開発日記 一覧

2002/03/13

この開発日記、最初から今まで1つのHTMLファイルで続いています。 というのも、XMLではファイルの分割が出来ないからです。
日記を記述した1つのXMLファイルを、XSLTを通すことにより複数に分割できないため このような1つのHTMLになっているわけです。
次のXSLTあたりの規格にはこういったファイル分割という機能も 盛り込まれるそうですので早くできてほしいですね。

try-finally構文

Javaには、try-catch-finally構文を、catch無しに使う方法があります。
例えば、ある関数からreturnする前に必ず何か後処理(ストリームのclose等) をやりたいと思っていて、そして関数の中には何回もreturnが出現するとき、 その全てのreturnの前に後処理を書かなければなりません。
これを避けるために、tryで処理全体を囲み、finallyに後処理を書きます。 そうすると、何も考えずにtryブロック中returnをしても、return前にfinally部が呼び出され、 後処理が行われてからreturnします。 こう書くことにより、後処理書き忘れミスが防げるわけです。

C++の例外機構は、try-catchだけですので、このような終了処理はありません。 ですので、C++でこれをするのは無理かな、と諦め半分にMSDNをfinallyで検索して みましたら、なんと、ありました。構造化例外処理というものです。

__try と __finallyを使えば同様のことができるようです。
これは、CでもC++でも使うことができるようです。
ですが、これはVC++専用の構文ですので、恐らく他のコンパイラでは 使用できないでしょう。
また、通常のC++の例外処理と同時に使うことも出来ません。
つまり、この構文は、いわゆる古い構文であるわけです。 ですので__try&__finallyの使用はまったくお勧めしませんが、 納期が迫っているがどこにミスがあるか分からない! なんて時には使ってみるのも良いかもしれません。

explicit宣言指定子

環境Visual C++ 6.0

C++言語には、explicit宣言指定子というものがあります。 VC++ではこれはどのように働いているのか調べてみました。 (他のC++コンパイラにおける動作は調べていません)

例えば、Hogeというクラスがあったとします。そして、

void Func(Hoge a);

というような関数があった場合、

Func(1);

と呼び出すと、コンパイラは、1をHogeクラスに変換できるかどうか 調べます。つまりはHogeのコンストラクタを呼び出して、

Hoge(1)

が解決できるかどうか調べるわけです。

クラスHogeに、例えば次のようなコンストラクタがあった場合、

Hoge(int a);

Hoge(1)はこのコンストラクタを呼び出すことにより解決できますので、 Hogeクラスの分のメモリを(スタックに)確保し、このコンストラクタを呼び出して初期化し、 関数Funcに渡すようなコードが生成されます。

他にも、次のようなコンストラクタでも同様のことが言えます。

Hoge(int a, int b = 0);

このコンストラクタでもHoge(1)は解決できます。 もちろん先ほどのコンストラクタが一緒にあった場合、Hoge(1)はどちらを使ったら良いのか 分かりませんので、コンパイルエラーとなります。

このように、引数が1つで呼び出せるコンストラクタは、型変換に使われます。
しかし、

Func(1);

という呼び出しを見ただけでは、Hogeクラスを使っているとは、普通気が付きません。 そのため、この変換は暗黙の型変換と言われるようです。 これはこれで便利なときはあるのですが、 プログラマがHogeを意識せずコードを書いてしまうこともあるため、 問題を引き起こす可能性があります。

Hogeクラスの設計者が、このような暗黙の変換を使いたくない場合、 つまり、このように

Func(Hoge(1));

とHogeを意識してコードを書いて欲しいと思ったときに使うのがexplicitです。
コンストラクタ前にexplicitキーワードを付けて、

explicit Hoge(int a);

としておくと、このようなコンストラクタが暗黙の型変換に使われそうになった時に、 コンパイルがエラーを発生させます。

Hoge(int a);
explicit Hoge(int a);

と2つコンストラクタを用意して、明示的な型変換と暗黙の型変換で 使い分けるということはできません。
explicitは暗黙の型変換コンストラクタとして選ばれない、というわけではなく、 暗黙の型変換として選ばれたコンストラクタにexplicitが付いていたら エラーがでるということのようです。
つまり、どのコンストラクタを型変換のために使うのかと選ぶ時は explicitかどうかは判定していないということです。

この話題は、MSDNでbasic_ifstreamのヘルプをみたとき、 デフォルトコンストラクタにまでexplicitが付いているのを疑問ったのが発端でした。 実際には、デフォルトコンストラクタにexplicit宣言指定子をつけても無意味のようです。

explicit Hoge()

とコンストラクタを宣言しても、

Hoge a

と()を付けずに問題なく使えます。 Hogeを派生させてHeroというクラスを作って、そのコンストラクタをこのようにして、

Hero::Hero(){}

明示的に基底クラスであるHogeを初期化しなくても、コンパイルエラーは発生しません。

fstreamヘッダファイルを覗いて、本当はどのように実装されているのかを見てみたところ、

basic_ifstream() : basic_istream<_E, _Tr>(&_Fb) {}

explicit宣言指定子が付いていません!
プログラミング言語C++第3版(日本語訳版)を見てみても、 basic_ifstreamのデフォルトコンストラクタにはexplicitは付いていないようです。 というわけで、どうやら実装は正しいようです。 たまにあるMSDNのミスに巻き込まれてしまっただけの模様です。 でもこのexplicit宣言指定子って活躍しているんでしょうかねぇ・・・

前の開発日記 次の開発日記 一覧