C++11
C++のポインタには、多くの興味深い性質がある:
コピーできる。
代入できる。
void *を総称的ポインタとして使える。
静的キャストで、基底クラスのポインタに変換できる。
動的キャストで、派生クラスのポインタに変換できる。
一方、C++のポインタには主に以下のような欠点や危険な性質がある:
動的に割り当てられたメモリを手動管理する責任がプログラマ側にある。
メモリ上の、不正なアドレスや未割り当てのアドレスが参照できる。
この問題を解消・軽減するためのイディオムとして、RAIIに基づいたスマートポインタがよく利用される。スマートポインタは、通常のポインタの利点を維持したまま、弱点を大幅に削ったものである。C++03までの標準C++ライブラリにもスマートポインタの一種としてstd::auto_ptrが存在したが、制約が多く、決して使いやすいとは言えなかった。C++11では、Boost C++ライブラリをベースとした、いくつかの新しいスマートポインタが標準化された。
クラステンプレートstd::shared_ptrは、同じオブジェクトに対する「同等の」参照をカウントする機能(参照カウント)を持ち、関連するスマートポインタ間でオブジェクトの所有権を共有する。さらに、標準コンテナの要素とすることも可能である。
同じオブジェクトを参照するポインタの数を得るには、shared_ptrのメンバ関数であるuse_countが使えるだろう。メンバ関数resetは、スマートポインタをリセットする。リセットされたポインタは「空」になり、use_countを呼び出すとゼロを返す。
以下に、shared_ptrの使用例を示す:
これと関連し、弱い参照としてstd::weak_ptrテンプレートも導入される。これもスマートポインタ・参照と同様に振舞うが、shared_ptrとの違いは、参照先の値がポインタによって「所有」されず、弱参照ポインタが存在していても破壊され得る点である。これは、弱参照ポインタには参照先オブジェクトが破壊されてしまうことによる実行時エラーが発生しやすいことを意味している。しかしこれにより、オブジェクトの生存時間に影響しない形で参照を持つことが可能となり、循環参照を防止できる。
このユーティリティは<memory>ヘッダに変更を必要とするが、C++言語拡張は必要としない。
また、std::unique_ptrが前述のauto_ptrの代わりとして導入され、auto_ptrは非推奨とされる。unique_ptrはauto_ptrの全機能を提供するが、左辺値からの暗黙的な移動の際に起こる挙動が異なる。unique_ptrは、C++11のMove Semanticsを用いたコンテナになっている。
コンピュータは決定的な振る舞いをするものであるが、疑似乱数による乱数列を生成することにより、(外見だけでも)非決定的な振る舞いが必要となるようなアプリケーションがある。
標準に用意されている方法は、rand関数のみである。しかし、十分な定義がされていないため、そのアルゴリズムは完全にライブラリ開発者に任せられている。新たな乱数生成ユーティリティは<random>ヘッダを通して定義される。他のヘッダやC++言語への修正は必要としない。
乱数生成器は、内部状態と、結果を計算し次の状態を生成するための関数をもつ。この2つの特性によって、乱数生成エンジンが定まる。他の特性として、生成結果や乱数の間隔や密度の分布も重要である。
新ライブラリには、数種の擬似乱数生成エンジンが導入される。これらはテンプレートクラスであり、必要に応じて特殊化できる。擬似乱数エンジンの内部状態は種(一般には変数の集合)によって決定される。
※使われる型の次元数・バイト数倍される。
エンジンの質はクラステンプレートdiscard_blockを用いて向上でき、クラステンプレートxor_combineと組み合わせることも可能である。利便性のため、<random>ヘッダには数種の標準エンジンが定義されている。例として、mersenne_twisterから実体化されるmt19937クラスを示す。
random_deviceクラスを用いて、unsigned int型の非決定的乱数を生成できる。実装には、システムから独立した入力を持つデバイス(例えば、非同期的な外部カウンタや、特殊なトランスデューサーなど)の使用や、伝統的な「結果を調節する」擬似乱数エンジンの使用が必要である。libstdc++やlibc++では、/dev/urandomを読み出す実装となっている。
新ライブラリには、一様分布から確率論で定義された分布まで、多種類の分布が定義されている:
離散一様分布uniform_int
ベルヌーイ分布bernoulli_distribution
幾何分布geometric_distribution
ポアソン分布poisson_distribution
二項分布binomial_distribution
連続一様分布uniform_real
指数分布exponential_distribution
正規分布normal_distribution
ガンマ分布gamma_distribution
明らかであるが、標準の分布を実体化しても構わないし、ユーザ自身の互換性のある分布を用いても構わない。
以下は、新ライブラリを用いた簡単な例である:
参照ラッパはテンプレートクラスstd::reference_wrapperのインスタンスとして得られる。参照ラッパは、C++言語の通常のリファレンス ('&') にも似ている。オブジェクトから参照ラッパを得るには、テンプレート関数std::refを使う(constな参照の場合はstd::crefが使用される)。
参照ラッパはテンプレート関数と使用する場合に有用であり、特に引数としてコピーではなく参照を取る必要がある場合に便利である:
この新ユーティリティは現在のに追加される。C++言語の拡張は必要としない。
なお、上記の高階関数テンプレートは、のちにC++17にて可変長引数テンプレートstd::invokeとして標準化されている。
関数オブジェクトの多相的ラッパ(「多態的関数オブジェクトラッパ」とも呼ばれる)は、意味的にも構文的にも関数ポインタに似ている。しかし、引数がラッパの引数型と変換可能である関数を参照できる点など、束縛が緩和されている。
次の例で、特性を理解できるだろう:
クラステンプレートstd::functionは<functional>ヘッダで宣言される。C++言語への変更は必要としない。
メタプログラミングとは、他のプログラム(もしくは自分自身)を生成、修正するプログラムを生成することである。これらの動作は、コンパイル時、もしくは実行時に発生する。C++標準化委員会は、テンプレートを通したコンパイル時メタプログラミング(テンプレートメタプログラミング)を可能にするライブラリの導入を決定した。
以下は、現在の標準でのメタプログラミングの例である: 指数計算に、テンプレート実体化の再帰を用いている。
多くのアルゴリズムは、型の違うデータに適用可能である。C++のテンプレートはジェネリックプログラミングをサポートし、より小さく有用なコードを作れる。それでも、アルゴリズムは使用されている型の情報を必要とすることも多い。この種の情報は、型特性を使用してテンプレートクラスの実体化時に展開できる。
型特性は、オブジェクトの分類やクラス(または構造体)の性質を示すものである。新ヘッダの<type_traits>で宣言される。
次の例は、関数テンプレートelaborateの例である。この関数は、渡されたデータ型に基づき、二つのアルゴリズム (algorithm.do_it) から一方を実体化する:
ヘッダ<type_transform>で定義された型特性を用いると、型変換の処理を生成することも出来る(static_castとconst_castはテンプレート中では不十分)。
この種のプログラミングで、美しく簡潔なコードを書ける。しかし、このテクニックの弱点はデバッグである。コンパイル時のデバッグは不適切であるし、プログラム実行時には非常に難しい。
テンプレート関数オブジェクトの戻り値の型を(コンパイル時に)決定するのに、直感的な方法がない。特に引数の型に基づいて決まる場合は顕著である。
例として以下のコードを挙げる:
calculusクラステンプレートをclearクラスで実体化する場合(calculus<clear>として実体化する場合)、calculus関数オブジェクトはclear関数オブジェクトと同じ戻り値型を持つ。
ここで、calculusクラステンプレートをconfusedクラスで実体化する場合(calculus<confused>として実体化する場合)を考えよう:
calculusの戻り値型はconfusedクラスと同じではない(calculus<confused>.operator()の実体化に伴い、intから doubleへの変換や逆変換が起こる)。
次期標準に提案されている新ライブラリで、result_ofクラステンプレートが導入され、各宣言ごとに関数オブジェクトの戻り値型の決定と使用が可能になる。これを用いて、関数オブジェクトの戻り値型を取得するようにすることでcalculusを修正した:
このようにすることで、関数オブジェクトcalculus_ver2<confused>の実体化の際に、型変換は発生しない。
関数オブジェクト呼び出し時の戻り値型の決定は、式の戻り値型を決定するという一般的な問題の一部である。将来的には、問題の起き得る箇所にdecltypeのような機能を使うことで解決されるだろう。