C++の参照に関する罠
開発現場で特に支障がなければ、必ずしも正確な基礎知識は必要でないかもしれません。しかし実際に、基礎知識の欠落が引き起こしたプログラムの不具合は少なくありません。以下のようなC++の関数がその典型例でしょう。
void example1(String str) { //strを参照し、何らかの処理を実行 }
この場合、引数str
は呼出し元からコピーされ、新しいオブジェクトとして生成されます。関数内でstr
を参照するだけであれば、引数を参照型に変更することでstr
の生成によるオーバヘッドが解消されます。
void example2(const String &str) { //strを参照し、何らかの処理を実行 }
これは、C++の基礎的な知識不足が主な理由と考えられますが、このようなコードを書いてしまうのは何もプログラミング初心者だけではありません。豊富な経験を持つC言語のプログラマでさえ、同様の傾向が見られるのです。C言語のプログラマであれば、ほとんどの場合、以下のような関数に違和感を感じるのではないでしょうか。
struct smp1 { ///いくつかの要素 }; void example3(struct smp1 parm) { /* parmを参照し、何らかの処理を実行 */ }
関数example3
を呼び出すと、引数の構造体が全てコピーされるので、オーバーヘッドが発生するとともにスタックを浪費します。これを見れば、ほとんどのC言語プログラマは、以下のように修正したくなるのではないでしょうか。
void example4(const struct smp1 *parm) { /* *parmを参照し、何らかの処理を実行 */ }
私の絡んだプロジェクトにおいても、何度か同じケースに出喰わしたことがありますが、C言語ではexample3
のような関数を作成しないプログラマでも、C++でクラスを使う場合にはexample1
のような関数を作成してしまうのです。動作そのものに問題ありませんが、非常に多く実行される場合などは、動作速度に著しく影響を与えることがあります。仮に、引数にクラスの値を受けとった場合の動きが完全に説明できなかったとしても、C++のクラスがCの構造体を拡張したものであることを知っていれば、直観的にexample1
の引数が問題になることに気が付くのではないでしょうか。これは、C++の基礎知識を理解していないことによる問題の典型例と言えます。