はじめに
C++でソフトウェアを作成する際に陥りがちなミスについて、いくつか実例を交えながら解説します。本題に入る前に、C++とはどんな言語なのか、またC++を学ぶことの意味について、簡単に私の考えを述べたいと思います。
初めてC++を開発で使用したのは、ファイルログ出力が中心のプログラムをコーディングする場面においてでした。見積りでは5人月のところを私一人で2ヶ月でやれ、という非常に厳しいスケジュールの中で、言語仕様を勉強しながらコーディングを行っていくことになりました。
これでは継承や多態などを勉強している時間はありませんので、カプセル化だけを意識してクラスを使い、コーディングしていく、という方針で進めました。とりあえずCにはない機能について軽くなめるように参考書を読み、コーディングに入りました。そして動かしてみると大量のバグ。標準のstring
を何も考えずに多用していたため、文字列リテラルに対して文字列の連結をしてしまっていたり、ローカル変数への参照を関数の戻り値として返してしまっていたりなどと、ひどいものでした。実行環境に恵まれていたため、実行速度は問題となりませんでしたが、改めて見ると非常に効率の悪いプログラムになっていました。
私のC++の経験はこういったスタートを切ったため、C++を習得するには何よりも、まず基礎知識が必要と強く感じました。機能の概要だけを知ったところで、基礎が身に付いていなければまともなプログラムは書けないこと、基礎が身についているからこそ多彩な機能を有効利用できることを改めて思い知らされたわけです。
対象読者
この記事の読者はC++を使ったことがある方を想定しています。
C++の特徴
上記のような読者に対しては意味が無いかもしれませんが、C++という言語の特徴について簡単に説明します。
オブジェクト指向をサポート
第1の特徴は、オブジェクト指向をサポートしているということです。
「カプセル化」「継承」「多態性」という、オブジェクト指向を特徴づける3つの機能をサポートしています。C++の前身であるC言語においても、データと処理をある程度「カプセル化」する事は可能でしたが、C++では、より完全な「カプセル化」を行うことができます。「継承」および「多態性」は、Cでは全くサポートされていませんでした。C++はCの単なる派生言語ではなく、C言語の資産を活用して開発された、新しいオブジェクト指向言語と言っても間違いではありません。
C言語のスーパーセット
第2の特徴は、C言語のスーパーセットであるということです。
C++はCの拡張版として生まれ、そして発展してきました(図1)。そのため、現在でもC++のコンパイラは完全にC言語の仕様をカバーしています。このことにより、現在までに蓄積されてきた多くのC言語のプログラミング資産との親和性が極めて高いという特徴を持っています。
また、同時にC言語の特徴も引き継いでいます(図2)。例えば、C言語は極めて実行効率の高い言語ですが、C++も極めて高い実行効率を持っています。C++が大きく普及した理由もここにあると私は考えています。
極めて高い柔軟性
第3の特徴は、実装において極めて自由度が高いという点が挙げられます。
もともとの起源であるCが、OSというハードウェアに近い領域のコードを書けるように開発されているので、やろうと思えば大概のことを実装できます。これはメリットであり、デメリットでもあります。自由度が高いことは、さまざまな目的を実現するという点においては大きなメリットですが、その一方で危険なコードも書く可能性があるというデメリットもあります。この記事で言及する落とし穴も、この特徴によって引き起こされています。
設計において適用できる概念の広さ
第4の特徴は、設計において適用できる概念の広さです。
C++は、C言語時代の構造化プログラミングに対応した形でコードを書くこともできますし、もちろんオブジェクト指向に則ったコードも書けます。また、これから広まっていくであろうジェネリックプログラミングにも対応しています。これはメリットでもありますが、デメリットでもあります。たとえば、C++を使ってオブジェクト指向で実装したつもりが、中途半端に構造化プログラミングとオブジェクト指向の混ざった構造になってしまうということが考えられます。その一方で、現在、数多く存在している構造化プログラミングに則って書かれたコードを活用しながら、オブジェクト指向に置き換えていけるのは便利です。既存の資産を活かしたまま、よりよく改造していくことができます。