C++ へようこそ (Modern C++)
C++ は世界で最も広く使用されているプログラミング言語の 1 つです。 適切に記述された C++ プログラムは、高速で効率的です。 この言語は、楽しめるゲームから、高性能な科学的ソフトウェア、デバイス ドライバー、埋め込みプログラム、さらに Windows クライアント アプリケーションに至るまで、幅広いアプリケーションの作成に使用でき、他の言語よりも柔軟性があります。 20 年以上にわたって、C++ はそれらをはじめとするさまざまなソリューション使用されてきました。 ますます多くの C++ プログラマが、旧来の C のプログラミング スタイルから卒業して、最新の C++ の手法を身に着けていることを、ご存知でない方もいるかもしれません。
C++ の最初の要件の 1 つは、C 言語との下位互換性でした。 それ以来、C++ はさまざまな進化をとげています。C 言語でのクラスの使用に始まり、最初の C++ 言語仕様が作成され、それに続く多くの拡張が行われてきました。 この経緯のため、C++ はマルチパラダイムのプログラミング言語と呼ばれることが多くあります。 C++ では、生のポインター、配列、null で終わる文字列、カスタム データ構造、その他の機能を使って、純粋な手続き型の C スタイルのプログラミングを行うことも可能です。これにより優れたパフォーマンスが可能となりますが、バグと複雑性も生じることになります。 C スタイルのプログラミングはそのようなリスクを抱えていたため、C++ の当初のねらいの 1 つは、タイプ セーフで、作成、拡張、保守の容易なプログラムを作成可能にすることでした。 C++ は、早い段階でオブジェクト指向プログラミングなどのプログラミング パラダイムを追加しました。 長年にわたり、十分に検証されたデータ構造やアルゴリズムの標準ライブラリと共に、さまざまな機能が言語に追加されました。 これらの拡張が最新の C++ のスタイルを可能にしています。
最新の C++ では下記のような点が強化されています。
ヒープまたは静的なグローバル スコープではなく、スタック ベースのスコープ。
明示的な型名ではなく、自動型推論。
生のポインターではなく、スマート ポインター。
生の char[] 配列ではなく、std::string と std::wstring の型 (「<string>」を参照)。
生の配列またはカスタム コンテナーではなく、vector、list、map などの標準テンプレート ライブラリ (STL) のコンテナー。 <vector>、<list>、および <map> を参照してください。
手動でコーディングされたアルゴリズムではなく、STL アルゴリズム。
例外はエラー状態の報告と処理のためだけに使用される。
通常のスレッド間通信機構ではなく、STL std::atomic<> を使用したロック制御不要のスレッド間通信 (<atomic> を参照)。
個別に実装される小さい関数ではなく、インライン ラムダ関数。
配列と共に使用可能な堅牢なループを作成できる範囲ベースの for ループ、STL コンテナー、および for ( for-range-declaration : expression ) フォームの Windows ランタイム コレクション。 これは、コア言語サポートの一部です。 詳細については、「範囲ベースの for ステートメント (C++)」を参照してください。
C++ 言語自体も進化しました。 次の 2 つのコード スニペットを比較してみます。 このスニペットは以前の C++ を使ったものです。
// circle and shape are user-defined types
circle* p = new circle( 42 );
vector<shape*> v = load_shapes();
for( vector<circle*>::iterator i = v.begin(); i != v.end(); ++i ) {
if( *i && **i == *p )
cout << **i << “ is a match\n”;
}
for( vector<circle*>::iterator i = v.begin();
i != v.end(); ++i ) {
delete *i; // not exception safe
}
delete p;
このスニペットは最新の C++ で同じことを行うものです。
#include <memory>
#include <vector>
// ...
// circle and shape are user-defined types
auto p = make_shared<circle>( 42 );
vector<shared_ptr<shape>> v = load_shapes();
for_each( begin(v), end(v), [&]( const shared_ptr<shape>& s ) {
if( s && *s == *p )
cout << *s << " is a match\n";
} );
最新の C++ では、スマート ポインターを使用できるため、新規/削除を使用したり、明示的な例外処理を使用する必要はありません。 auto 型推論とラムダ関数を使用すると、コードをすばやく記述して、それを引き締め、より的確に把握することができます。 ってきた方、特に型の大部分が参照型であり、値型が非常に少ない、他のマネージ言語から移ってきた方は、C++ のクラスは既定で値型であることに注意してください。さらに for_each を使用すると、簡単にすっきりしたコードを記述でき、for ループを使用するよりも、意図しないエラーを生じることが少なくなります。 スケルトン コードを使って、最小限のコードでアプリケーションを記述できます。 さらにそのコードを例外セーフでメモリ セーフにすることができ、割り当て/解放や、エラー コードを取り扱う必要はありません。
最新の C++ では、2 種類のポリモーフィズムが組み込まれています: コンパイル時にテンプレート経由によるもの、および実行時に継承と仮想化によるものです。 2 種類のポリモーフィズムを活用することにより、優れた効果を生じることができます。 STL テンプレート shared_ptr は、内部仮想メソッドを使用して、型消去を非常に簡単に行うことができます。 ただし、テンプレートが最適な選択である場合には、ポリモーフィズムの仮想化を過度に使用しないでください。 テンプレートは非常に強力です。
他の言語から C++ に移ってきた方、特に型の大部分が参照型であり、値型が非常に少ない、他のマネージ言語から移ってきた方は、C++ のクラスは既定で値型であることに注意してください。 ただし、それらを参照型として指定して、オブジェクト指向プログラミングをサポートするポリモーフィックな動作を可能とすることもできます。 値型はメモリとレイアウト コントロールに関するものであり、参照型はポリモーフィズムをサポートする基底クラスと仮想関数に関するものであることを理解すると、役に立ちます。 既定では、値型はコピー可能で、それぞれにコピー コンストラクターとコピー代入演算子があります。 参照型を指定する場合は、コピー コンストラクターとコピー代入演算子を無効化して、クラスをコピー不可にし、ポリモーフィズムをサポートする仮想デストラクターを使用します。 また値型はコンテンツに関するものであり、コピーされるときに、それぞれ変更可能な 2 つの個別の値を持ちます。 一方、参照型はオブジェクトがどのようなものであるかについての識別に関するものであり、このためポリモーフィックな型として参照される場合もあります。
再びパワーが重要視されてきているため、C++ にとってのルネサンスが訪れています。 プログラマの生産性が重要である場合には Java や C# などの言語が適していますが、パワーとパフォーマンスがより重要である場合には、それらの言語には限界があります。 高い効率性とパワーに関しては、特に制限のあるハードウェアによるデバイスでは、最新の C++ に勝るものはありません。
言語が最新であるだけでなく、開発ツールも最新です。 Visual Studio により、開発サイクルのすべての部分が堅牢で効率的になります。 これにはアプリケーション ライフサイクル管理 (ALM) ツール、IntelliSense などの IDE の強化、XAML などのツールに適した方法、ビルド、デバッグ、および他のツールが含まれています。
ドキュメントのこの部分の記事は、最新の C++ プログラムを作成するために、最も重要な機能および技術に関する、高レベルのガイドラインとベスト プラクティスを提供します。
詳細については、StackOverflow の記事「C++11 で推奨されない C++ の表現形式」を参照してください。