Nobember 29, 2023
C++プログラミング言語の略史
*本記事は Perforce Software社の以下のブログ記事(2024年4月4日時点)の参考訳です。
A Brief History of C++
*ブログの内容は更新されている可能性があります。
MISRA C++の新版MISRA C++:2023®がついにリリースされます。皆様の新規格への対応をサポートするため、Perforce Software社のPrincipal Techinial Support EnginerであるDr. Frank van den BeukenによるMISRA C++:2023 ブログシリーズの第2弾をお届けします。
本ブログでは、C++プログラミング言語がこれまでどのように進化してきたのか、その歴史を振り返りつつ、今後の展開について見ていきましょう。
ブログシリーズ第1弾「MISRA C++:2023®について知っておくべきこと」はこちら
目次
はじめに:C++の歴史
C++は、広く一般的に使用されているプログラミング言語です。
非常に効率性の高いプログラムの記述ができるため、MISRAが標準的なコーディングスタンダードとなっている自動車業界をはじめ、セーフティクリティカルなアプリケーションの開発でよく使われています。
ここからは、そんなC++の歴史について見てみましょう。
C++の始まり
C++は、1979年にAT&Tベル研究所でデンマーク人コンピュータ科学者であるBjarne Stroustrup氏によって発明されました。ネットワーク上で、UNIXカーネルのディストリビューションがどの程度可能かを分析する過程で生まれました。
Stroustrup氏は、ケンブリッジ大学のコンピューティング研究所で博士論文に取り組んでいたときに、Simulaプログラミング言語のプログラム構成と並行処理の機能に感銘を受け、シミュレータの記述に使用しようと思い立ちました。しかし、その実装段階で、スケーリングが思うようにいかなかったため、最終的にはBCPLでの記述に切り替えたようです。
C with Classes
AT&Tベル研究所に入ってから、Stroustrup氏はSimula言語の機能のうち、自身が特に便利だと思うものを用いて、C言語の強化を図ろうと決めました。そして、Simulaのようなクラスを持つCプログラムを、既存のコンパイラでコンパイル可能な通常のCコードに変換するプリプロセッサ「Cpre」の開発に着手しました。この新言語は当初、単に"C with Classes"と呼ばれました。
C言語が使えるものにはすべて使えるようにしよう。そんな汎用的なプログラミング言語を目指して、この新言語の開発は始まりました。当時、既にCコンパイラが多くのプラットフォームで利用されていたため、この新言語でもその移植性は引き継がれており、現在でも重要な特性のひとつとなっています。また、この言語の開発においては、C言語の効率性とハードウェア機能への直接的なアクセスを維持しつつ、C言語の安全でない機能に対して、より良い代替手段を提供することも目的とされていました。
C with Classesで提供された新機能には以下のようなものがあります。
- クラス
- 派生クラス
- public/privateアクセス制御
- コンストラクタとデストラクタ
- call関数とreturn関数(※開発者にあまり好まれなかったため、後に廃止)
- フレンドクラス
- 関数引数の型チェック
- インライン関数
- デフォルト引数
- 代入演算子のオーバーロード
C++
ここに至り、この新しい言語に適切な名前が必要になってきました。しばらくの間は「C84」と呼ばれていましたが、紛らわしく、あまり洗練されていない名称だと考えられていました。最終的に、C言語の後継というような意味合いで、コンピュータ科学者の Rick Mascitti氏から「C++」という名前が提案されました。
さらに、C++の機能が増え、Cpreプリプロセッサでは対応しきれなくなったことから、「Cfront」という新しいコンパイラも作られました。便宜上、Cコードの生成もまだ行うコンパイラでしたが、これにより、構文とセマンティクスの完全なチェックに加え、プログラムの内部表現をスコープごとのシンボルテーブルと共に生成することが可能になりました。
新しい言語機能として、以下のようなものが追加されました。
- 仮想関数
- 関数名と演算子オーバーロード
- 参照
- const(定数)
- ユーザー制御によるフリーストアを使用した動的メモリ管理
- 改良された型チェックとC++スタイルのコメント(※BCPLを参考にしている)
1986年には、Cfront 1.0コンパイラをベースに、C++言語に関して説明した最初の本『C++プログラミング言語』が出版されました。
C++ バージョン 2.0
1989年には、定義と実装の安定性が増した、C++の次のバージョンが完成しました。
C++ バージョン 2.0では以下のような機能が追加されています。
- 多重継承
- リンク時に型の安全性を保証
- 関数のオーバーロード解決を改善
- 代入や初期化の再帰的定義
- ユーザー定義のメモリ管理を改善
- 抽象クラス
- 静的メンバ関数
- constメンバ関数
- protectedメンバ
- ->演算子のオーバーロードとメンバへのポインタ
C++ バージョン 3.0
C++ 3.0は、C++が標準化される前の最後のバージョンです。1991年に完成し、クラスと関数のテンプレートが追加されています。1993年には、HP(ヒューレット・パッカード)が1992年に初期実装を行った例外処理に対応する、C++ 4.0のリリースが予定されていましたが、これは完成には至りませんでした。
注解C++リファレンス・マニュアル
AT&Tによる新しいC++コンパイラの開発計画は実現しなかったものの、(Borland、IBM、DEC、Microsoftなどによる)商用のC++コンパイラや、オープンソースのGNUコンパイラ「g++」が登場しました。その結果として、Stroustrup氏は、C++言語自体の開発やその標準化の方に注力するようになりました。1991年に出版された『注解C++リファレンス・マニュアル』は、C++標準化の出発点と言えるでしょう。このマニュアルは、Cfront 3.0で実装された機能だけでなく、C++の定義についてもしっかりと解説がされており、様々な組織に所属する人々から多くのレビューを受けたものになっています。新機能としては、名前空間や内部クラス、例外処理などの説明があります。
C++98
1989年、HPがAT&T、DEC、IBMと共同でC++のANSI標準化を開始しました。言語の標準化が必要になった理由はいくつかありますが、重要な新機能の追加や、互換性のない方言(dialect)の開発の防止などが挙げられます。1991年にはISOが標準化を開始したことで、ISO委員会による合同会議が開催されるようになりました。
C++98では、標準テンプレート・ライブラリ(STL)をはじめとする、標準ライブラリの定義がなされ、以下のような機能も追加されました。
- 実行時の型識別(RTTI:dynamic_cast、typeid)
- 共変戻り値の型
- キャスト演算子
- mutable
- bool
- 条件文における宣言
- メンバのテンプレート
- クラス内メンバの初期化
- テンプレートの個別コンパイル(エクスポート)
- テンプレートの部分的な特殊化
- オーバーロード関数テンプレートの部分的な順序付け
C++03とEmbedded C++
C++03は、C++98にあった技術的な誤植などの修正を目的にリリースされたバージョンです。ただ、リリース当時、ISO委員会では既に次のバージョンの検討も始まっていました。
一方で、東芝や日立製作所、富士通、NECをはじめとした日本の組込みシステムツール開発者によるコンソーシアムから、組込みシステムのプログラミング向けに、Embeded C++(EC++)サブセットの提案がなされたのもこの頃です。このサブセットでは、組込みシステムのパフォーマンスを低下させる可能性のある言語機能や、開発者にとって複雑すぎるために生産性や正確性を損なうと恐れがあると考えられる言語機能が削除されました。
具体的には、多重継承、テンプレート、例外処理、RTTI、新スタイルのキャスト、名前空間などの機能が該当します。また、STLやロケールが標準ライブラリから削除され、iostreamsの代替機能が提供されました。興味深いことに、EC++自体はあまり普及せず、テンプレートを追加したスーパーセット「Extended EC++」の方がよく使われました。
EC++に対する形で、ISO委員会はC++のパフォーマンスに関する技術報告書を発行しました。その報告書では、C++の様々な言語機能およびライブラリ機能の使用によって生じる可能性のある時間と空間のオーバーヘッドのモデルが示されました。これにより、パフォーマンスの問題への懸念に対応するとともに、効率的な実装のためのテクニックが提示されました。結果、ISO委員会により、EC++が承認されることはありませんでした。
C++11
C++11では数多くの新機能が導入されました。そのため、まるで新しい言語のように感じたプログラマーも多かったのではないでしょうか。
C++11では、以下のような機能が追加されました。
- メモリモデル(Memory model)
- 並行プログラミング(Concurrency)
- Auto and decltype
- 範囲for文(Range-for)
- ムーブセマンティクスと右辺値参照(Move semantics and rvalue references)
- 一様初期化(Uniform initialization)
- Nullptr
- Constexpr関数(Constexpr functions)
- ユーザー定義リテラル(User-defined literals)
- 生文字列リテラル(Raw string literals)
- 属性(Attributes)
- ラムダ式(Lambdas)
- 可変引数テンプレート(Variadic templates)
- エイリアステンプレート(using)(Template aliases (using))
- Noexcept
- Override and final
- Static_assert
- Long long
- メンバ変数のデフォルト初期化(Default member initializers)
- コンストラクタ内での初期化(Initialization in a constructor)
- 列挙型クラス(Enum classes)
標準ライブラリにも様々な追加がありました。1998年には、ピアレビューを受けたポータブルなC++のソースライブラリを無料提供するBoostという組織が発足しました。様々なライブラリ機能が早くから利用可能で、それらの利用から得られた経験がISO規格に生かされたという点で、Boostライブラリは重要な役割を果たしたと言えるでしょう。また、メモリモデルにより、スレッドやロックを通じた並行プログラミングのサポートが可能になりました。
ムーブセマンティクスは、プロジェクトが大きくなるにつれ膨大になる、不必要なコピーを削除することで、プログラミングの効率を向上させることができます。リソースのコピーを行うか、その所有権を別のオブジェクトに移すかを開発者が制御できるようにすることで、オブジェクトの有効期間やリソースの管理を可能にします。
C++14
C++14は、C++11の不足している部分を補った改良版としてリリースされたもので、以下のような機能が追加されています。
- 2進数リテラル(0b)(Binary literals (0b))
- 桁区切り文字(Digit separators)
- 変数テンプレート(Variable templates)
- 関数戻り値の型推論(Function return type deduction)
- ジェネリックラムダ(Generic lambdas)
- constexpr変数内のローカル変数(Local variables in constexpr functions)
- Move capture
- tuble内の特定の型の要素へのアクセス(Accessing a tuple by type)
- 標準ライブラリ内のユーザー定義リテラル(User-defined literals in the standard library)
C++17
C++17は、C++14のマイナーリリースの後のメジャーアップデートとなる予定でした。しかし、残念なことに、コンセプトやコルーチンといった期待されていた機能のいくつかは追加されないまま、リリースされることになりました。
C++17で追加された主な新しい機能は以下の通りです。
- クラステンプレート引数の推論(推論ガイド含む)(Class template argument deduction (introducing deduction guides))
- 構造化束縛(Structured bindings)
- インライン変数(Inline variables)
- 畳み込み式(fold expression)(Fold expressions)
- 条件式の明示的なテスト(Explicit test in conditions)
- 値のコピーの省略を保証(Guaranteed copy elision)
- 式の評価順序の厳密化(Stricter expression evaluation order)
- テンプレート引数型としてのauto(Auto as a template argument type)
- 一般的なミス防止のための標準属性の追加(Standard attributes to catch common mistakes)
- 十六進浮動小数点リテラル(Hexadecimal floating-point literals)
- "if constexpr"
追加された新機能を見ると、関数型プログラミングのサポートが今まで以上に強化されていることが分かると思います。関数型プログラミングに必要な要素としては既に、C++11でラムダ式が導入されていますが、畳み込み式(演算子を使って引数のリストをひとつの値にまとめられる便利な記法)や推論ガイドによって、より関数的なプログラミングが可能になりました。
C++20
C++20では、C++17では実現できなかった、コンセプトやコルーチンといった機能が追加されました。その結果、このバージョンはC++03からC++11へのアップグレードに匹敵する大きな進化を遂げました。C++17で予定されていたメジャーアップグレード版になったと言えるでしょう。
C++20で新たに加わった主な言語機能は以下の通りです。
- コルーチン(Coroutines)
- コンセプト(Concepts)
- モジュール(Modules)
その他に追加された新しい言語機能としては、コンパイル時計算(compile-time computation support)、スペースシップ演算子<=>(spaceship operator <=>)、並行処理(concurrency)の改善、指定初期化子(designated initializers)、文字列リテラルも使用可能な非型テンプレート・パラメーターのクラス型(class types in non-type template parameters)などがあります。また、新しい標準ライブラリ機能として、range、date、span、formatが追加されました。
モジュールの登場でようやく、C言語から継承されてきたインクルードファイルのメカニズムによる(つまり、プリプロセッサを用いる)方法よりも、優れたモジュール化表現が可能になりました。そして、順次実行される一連のコードの非同期実行を可能にする、スタックレスなメカニズムがコルーチンによって提供されました。コンセプトは、テンプレートの引数に対する要求を名前付きの集合として定義したものであり、テンプレートのインターフェースの一部です。コンセプトが導入されたことにより、テンプレートの使用目的を指定することが可能になり、制約が満たされない場合に発生するコンパイルエラーのメッセージが大幅に分かりやすくなりました。"SFINAE"(Substitution Failure Is Not An Error:置換の失敗はエラーにならない)を使用する今までのやり方では、コンパイルエラーが長く複雑になっていたので、この点は大きな改善と言えるでしょう。
C++の今後
C++言語は1979年の誕生から長い時を歩んできました。そして、これからも進化を続けていくことでしょう。
細かくも、重要なアップデートを含んだC++23が間もなくリリースされる予定ですが、C++26の開発も既に始まっています。
C++の人気は高まり続けており、Unreal Engineを使ったVR(仮想現実)や暗号通貨向けアプリケーションの開発など、その用途は拡大しています。
C++開発にPerforce Software社の静的解析ツールを
Perforce Software社の静的解析ツール「Helix QAC」と「Klocwork」は、30年以上にわたり、C/C++をはじめ、様々なプログラミング言語で安心安全かつ高品質なコードを書くために使われてきました。セーフティクリティカルなソフトウェア開発における使用に適したツールとしての認証も受けており、コードの問題や脆弱性、コンプライアンス違反などの検出することができます。
さらに、Helix QACには様々な規格・ガイドラインへの準拠をサポートするコンプライアンスモジュールも各種用意されています。MISRA C++:2023のルールを100%カバーしたコンプライアンスモジュールも、新ガイドラインの発行に合わせてリリース予定です。
MISRA C++:2023コンプライアンスモジュール is Available Now!!
MISRA C++:2023コンプライアンスモジュールは既に日本でも提供を開始しています。ご興味のある方は、製品ページをご覧いただくか、以下までお問合せください。