一般のプログラマの多くは、プログラミング言語というものを、ごく浅い表面的な理解だけで使っている。これは、いわゆる﹁入門書﹂によるところが大きい。入門書は、言語をできるだけパターンで教えようとする。かくかくしかじかの場合には、とらとらうまうまのように書いておけばいい、などといった具合だ。
たとえば、配列の全要素や、aggregateの全メンバーをゼロで初期化したいとする。多くのC++プログラマは、以下のように書く事であろう。
int a[100] = {0} ;このコードは、正しく動く。配列aの要素は、すべてゼロで初期化される。しかし、C++という言語を考えた場合、{0}と書く必要はない。空の{}で十分なのである。
int a[100] = {} ;では何故、多くのC++プログラマは{0}と書くのか。それは、多くの参考書が、そのように書いているからに過ぎない。大多数のC++プログラマは、どうも{0}を、特別な文法か何かのように錯覚しているようである。 そもそも、以下のコードはどういう意味なのか。
T x = {0} ;これは、﹁Tの最初の要素あるいはメンバーを、0で初期化し、その他をすべて、staticストレージと同じ方法で初期化する﹂という意味である。staticストレージは、明示的に初期化子を欠かなくても、必ずzero-initializedされる。そのため、このような意味になる。たとえば以下のように書けば、
int a[3] = {100} ;
﹁a[0]を100で初期化し、a[1]とa[2]はゼロ初期化する﹂という意味になる。
しかし、それだったら最初から、すべてstaticストレージと同じ方法で初期化する意味で書けばいいのだ。
int a[1000] = {} ; // すべての要素をstaticストレージと同じ方法で初期化(すなわち、ゼロ初期化)すでに述べたように、なぜ、いまだに多くのC++プログラマが{0}と書くかというと、多くの参考書がそう書いているからだ。なぜ、多くの参考書がこう書いているかというと、C言語では、空の初期化リストは書けなかったのだ。
int a[5] = { } ; // C言語ではエラー、C++ではOKこれは、C++による改良である。C言語の文法は絶望的に汚い。近年のC言語の文法がいくらかましになっているのは、C++のおかげであると言える。ところが、C99ですら、いまだに空の{}を認めていない。C99は、C++なら、わざわざ言語機能にするほどでもないようなものまで、言語機能にしていたりと、かなり迷走している。また、次のC言語規格も、悲惨である。C言語に未来はない。 配列や構造体の中身をゼロで初期化したいというのは、プログラミングにおいては、かなり一般的な要求であった。そのため、{0}というおまじないのような記法が生まれることになり、あまりに多用されたため、多くのプログラマは、{0}が特殊なルールででもあるかのように錯覚しているのである。 ほとんどのプログラマは、言語を、厳密な規格の定義を読んで理解することなく、信じられないほど簡略化された、参考書によって、表面的に理解している。 たとえばdynamic_castは、polymorphicな基本クラスのポインターやリファレンスを、派生クラスのポインターやリファレンスに、実行時の型情報のチェック付きで変換するという機能を提供している。しかし、dynamic_castは、派生クラスのポインターやリファレンスから、基本クラスのポインターやリファレンスに変換するという機能も提供している。
struct Base { } ;
struct Derived : Base { } ;
int main()
{
Derived d ;
Base & b = dynamic_cast< Base & >(d) ;
}
これは、static_castを使った場合と、全く同じである。実行時チェックも入らない。なぜならば、この型変換は、静的に行うことができるからだ。ある型が派生クラスであるということは、必ず基本クラスでもあるのだ。実行時チェックの入りようがない。しかし、多くのプログラマは、dynamic_castでは、必ず実行時チェックが入るものだと勘違いしている。何故このような機能があるのかというと、結局のところ、dynamic_castは、クラスヒエラルキーのナビゲーションのために使うものであり、一貫性をとるためではなかろうかと思われる。
同様にして、const_castで、CV-qualifierを付け加えることもできるし、まったく同じCV-qualifierにすることもできる。
int main() { int const * ptr = nullptr ; const_cast< int const *>( ptr ) ; }これも結局、const_castというのは、CV-qualifierの増減に関する機能であり、CV-qualifierを減らすだけしか認めないのであれば、どうも一貫性にかけるのであろう。 ではなぜ、参考書の著者が、もっとも厳密に言語を教えないのかというと、結局、そこまで厳密に知っていても、通常のプログラミングには、あまり役に立たないためであろう。しかし、今日もネット上では、もし規格を数行読んでいたら、疑問の沸きようがない文法上の問題に対して、喧々諤々の論争が繰り広げられている。 追記‥ さらに厳密に言うと、C言語とC++では、言語の定義の文面が異なる。対応する初期化リストの要素のないアグリゲートのメンバーは、C言語では、staticストレージと同じ方法で初期化される︵つまりゼロ初期化される︶。C++では、値初期化︵value-initialize︶される。値初期化では、アグリゲートとなりうる型はすべて、ゼロ初期化される。 もっとも、これらは単なる定義方法の違いというだけに過ぎない。
11 comments:
迷走の typo ですね September 18, 2010 at 2:27 PM
文法の綺麗さとか所詮はマニア好みなネタにすぎないわけで、 20年後も30年後もC言語は第一線ですよ 残念ながらね November 8, 2010 at 11:13 PM
私の想像では﹁いやいやそれはない。int a[10]; memchr(a, '\0', sizeof a);と書くんだ﹂という答えが返ってくるというのが一番多そうだと思っているのですが。 October 1, 2011 at 2:03 AM
>C言語に未来はない パワーワードなので勘違いを呼ぶみたいですが、意図はなんとなく分かりますよ。 Cが今後何十年か一線で使用され続けるのはおそらく間違いないが、言語の未来を考えたときに、バグや可読性低下の温床なので、凄まじく方言の多すぎるCはやめて、ゆくゆくはC++に置き換えられるべきってニュアンスですよね。 August 30, 2019 at 10:53 AM
Post a Comment