C++11 は、国際標準化機構(ISO) と国際電気標準会議(IEC)によるC++プログラミング言語の共同技術標準ISO/IEC 14882のバージョンです。C++11は、以前のバージョンの C++ 標準であるC++03 [ 1 ]を置き換え、後にC++14に置き換えられました。この名前は、仕様の発行年で言語バージョンに名前を付けるという慣例に従っていますが、 2010 年より前に発行される予定だったため、以前はC++0xと呼ばれていました。[ 2 ]
設計目標の一つはコア言語の変更よりもライブラリの変更を優先することであったが、[ 3 ] C++11 ではコア言語にいくつかの追加が行われた。大幅に改善されたコア言語の領域には、マルチスレッドのサポート、ジェネリックプログラミングのサポート、統一初期化、パフォーマンスなどがある。また、 C++ 標準ライブラリにも大幅な変更が加えられ、数学特殊関数ライブラリを除くC++ テクニカル レポート 1 (TR1)ライブラリのほとんどが組み込まれた。[ 4 ]
C++11 はISO/IEC 14882:2011 [ 5 ]として 2011 年 9 月に発行され、有料で入手可能です。発行された C++11 標準に最も近い作業草案は、2012 年 1 月 16 日付けの N3337 [ 6 ]で、 C++11 標準からの編集上の修正のみが含まれています。[ 7 ]
C++11はClang 3.3以降[ 8 ]およびGNU Compiler Collection(GCC)4.8.1以降[ 9 ]で完全にサポートされました。
設計委員会は、C++11の設計において、いくつかの目標を堅持しようと試みた。
初心者への配慮は重要だと考えられている。なぜなら、ほとんどのコンピュータプログラマーは常に初心者であり、多くの初心者は知識を広げることなく、自分が専門とする言語の側面での作業に限定してしまうからである。[ 2 ] [ 3 ]
C++委員会の役割の一つは、言語コアの開発です。コア言語において大幅に改善された分野には、マルチスレッドサポート、汎用プログラミングサポート、統一的な初期化、そしてパフォーマンスの向上などが挙げられます。
これらの言語機能は、主にメモリ使用量または計算速度のいずれかにおいて、何らかの実行時パフォーマンス上の利点を提供するために存在します。
C++03(およびそれ以前)では、一時変数(代入の右辺に位置することが多いため「 rvalue 」と呼ばれる)は、Cと同様に決して変更できないものとされ、型と区別できないと考えられていました。しかし、場合によっては一時変数が変更されることもあり、その動作は有用な抜け穴とさえ考えられていました。[ 10 ] C++11では、新しい非const参照型が追加されました。const T&rvalue 参照。これは、初期化後に変更が許可される一時変数を指し、ムーブセマンティクスを可能にするためのものです。T&&
C++03 の慢性的なパフォーマンス問題は、オブジェクトが値渡しされる際に暗黙的に発生する、コストのかかる不要なディープコピーstd::vector<T>です。この問題を説明するために、一時オブジェクトが内部的には定義済みのサイズの C スタイルの配列をラップしていることを考えてみましょう。std::vector<T>一時オブジェクトが関数から作成または返された場合、新しい一時オブジェクトを作成しstd::vector<T>、右辺値のすべてのデータをそこにコピーすることによってのみ、一時オブジェクトを格納できます。その後、一時オブジェクトとそのすべてのメモリは破棄されます。(説明を簡略化するため、この説明では戻り値の最適化は省略します。)
C++11では、のムーブコンストラクタはstd::vector<T>、への右辺値参照を受け取り、std::vector<T>内部のCスタイルの配列へのポインタを右辺値から新しいにコピーしstd::vector<T>、右辺値内のポインタをnullに設定できます。一時オブジェクトは二度と使用されないため、どのコードもnullポインタにアクセスしようとはせず、ポインタがnullであるため、スコープ外になったときにメモリが削除されません。したがって、この操作はディープコピーのコストを回避するだけでなく、安全で目に見えません。
右辺値参照は、標準ライブラリ以外の変更を加えることなく、既存のコードにパフォーマンス上のメリットをもたらします。一時オブジェクトを返す関数の戻り値の型を明示的に変更してムーブコンストラクタを呼び出すstd::vector<T>必要はありません。一時オブジェクトは自動的に右辺値とみなされるためです。(ただし、 C++03 バージョンでムーブコンストラクタがない場合は、コピーコンストラクタが呼び出され、大量のメモリ割り当てが発生します。)std::vector<T>&&std::vector<T>const std::vector<T>
安全上の理由から、いくつかの制限が設けられています。名前付き変数は、たとえ右辺値として宣言されていても、右辺値とはみなされません。右辺値を取得するには、関数テンプレートをstd::move()使用する必要があります。また、右辺値参照は特定の状況下でのみ変更可能であり、主にムーブコンストラクタで使用することを想定しています。
右辺値参照の記述方法の性質、および左辺値参照(通常の参照)の記述方法の変更により、右辺値参照は開発者が完全な関数転送を実現できるようにします。可変引数テンプレートと組み合わせることで、この機能は、特定の引数を受け取る別の関数に引数を完全に転送できる関数テンプレートを作成できます。これは、コンストラクタパラメータを転送し、特定の引数に対して適切なコンストラクタを自動的に呼び出すファクトリ関数を作成する場合に最も役立ちます。これは、C++ 標準ライブラリのemplace_backメソッド群で確認できます。
C++には、常に定数式という概念がありました。定数式とは3 + 4、コンパイル時と実行時で常に同じ結果を返す式のことです。定数式はコンパイラにとって最適化の機会であり、コンパイラはコンパイル時に定数式を実行し、その結果をプログラムにハードコーディングすることがよくあります。また、C++の仕様では、いくつかの箇所で定数式の使用が義務付けられています。配列を定義するには定数式が必要であり、列挙子の値も定数式でなければなりません。
しかし、定数式には関数呼び出しやオブジェクトコンストラクタを含めることは決して許されません。したがって、次のような単純なコードは無効です。
int getFive () { return 5 ; }int someValue [ getFive () + 7 ]; // 12個の整数からなる配列を作成します。不正なC++これはC++03では無効でした。なぜなら、getFive() + 7これは定数式ではないからです。C++03コンパイラはgetFive()、実行時にこれが実際に定数であるかどうかを知る方法がありません。理論的には、この関数はグローバル変数に影響を与えたり、他の非実行時定数関数を呼び出したりする可能性があります。
constexprC++11では、関数またはオブジェクトコンストラクタがコンパイル時定数であることを保証できるキーワードが導入されました。 [ 11 ]上記の例は次のように書き換えることができます。
constexpr int getFive () { return 5 ; }int someValue [ getFive () + 7 ]; // 12個の整数からなる配列を作成します。有効なC++11コードです。これにより、コンパイラはそれがgetFive()コンパイル時定数であることを理解し、検証することができる。
関数に `this` を使用すると、constexprその関数が実行できる処理にいくつかの制限が課されます。まず、関数は `void` 以外の戻り値型を持つ必要があります。次に、関数本体では変数の宣言や新しい型の定義はできません。さらに、本体には宣言、空文字列、および 1 つの `return` 文のみを含めることができます。引数の置換後、`return` 文の式が定数式となるような引数値が存在する必要があります。
C++11 より前は、変数の値は、変数が const として宣言され、定数式である初期化子を持ち、かつ整数型または列挙型である場合に限り、定数式で使用できました。C++11 では、constexprキーワードで定義されている変数は整数型または列挙型でなければならないという制限がなくなりました。
constexpr double EARTH_GRAVITATIONAL_ACCELERATION = 9.8 ; constexpr double MOON_GRAVITATIONAL_ACCELERATION = EARTH_GRAVITATIONAL_ACCELERATION / 6.0 ;このようなデータ変数は暗黙的に定数であり、定数式である初期化子を持つ必要があります。
ユーザー定義型から定数式データ値を構築するには、コンストラクタを で宣言することもできますconstexpr。constexprコンストラクタの関数本体には宣言と null ステートメントのみを含めることができ、関数と同様に変数を宣言したり型を定義したりすることはできませんconstexpr。引数置換後にクラスのメンバーを定数式で初期化するような引数値が存在する必要があります。このような型のデストラクタは自明でなければなりません。
コンストラクタを持つ型のコピーコンストラクタconstexprも、通常はコンストラクタとして定義する必要があります。constexprこれにより、constexpr 関数からその型のオブジェクトを値渡しで返すことが可能になります。クラスのメンバ関数(コピーコンストラクタ、演算子オーバーロードなど)は、constexprconstexpr 関数の要件を満たしていれば、として宣言できます。これにより、コンパイラはコンパイル時にオブジェクトをコピーしたり、オブジェクトに対して操作を実行したりすることができます。
constexpr 関数またはコンストラクタが定数式ではない引数で呼び出された場合、その呼び出しは関数が constexpr ではないかのように動作し、結果として得られる値は定数式ではありません。同様に、constexpr 関数の return 文内の式が特定の呼び出しに対して定数式に評価されない場合、結果は定数式ではありません。
constexprC++20constevalで導入された とは異なり、 は常にコンパイル時定数を生成する必要があるのに対し、 にはこの制約はありません。constexpr
C++03 では、クラスまたは構造体がプレーン オールド データ(POD) 型とみなされるためには、いくつかの規則に従う必要があります。この定義に合致する型は、C と互換性のあるオブジェクト レイアウトを生成し、静的に初期化することもできます。C++03 標準では、コンパイラがプログラムを受け入れられない技術的な理由がないにもかかわらず、C と互換性がある型や静的に初期化できる型に制限があります。誰かが C++03 POD 型を作成し、仮想メンバ関数を追加した場合、メモリ レイアウトに変更がないにもかかわらず、この型はもはや POD 型ではなくなり、静的に初期化できず、C と互換性がなくなります。
C++11 では、POD の概念をtrivialとstandard-layout という2 つの別々の概念に分割することで、POD のルールのいくつかが緩和されました。
自明な型は静的に初期化できます。またstd::memcpy()、コピーコンストラクタを使用する必要がなく、データコピーも有効です。自明な型のライフタイムは、コンストラクタが完了したときではなく、ストレージが定義されたときに始まります。
自明なクラスまたは構造体とは、次のようなものと定義される。
X() = default;)を使用できます。コンストラクタが自明となるのは、クラスに仮想メンバ関数がなく、かつ仮想基底クラスも存在しない場合に限られます。コピー/ムーブ操作を行うには、すべての非静的データメンバが自明である必要があります。
標準レイアウトの型とは、メンバーをC言語と互換性のある方法で順序付け、配置する型のことです。クラスまたは構造体は、定義上、以下の条件を満たす場合に標準レイアウトとなります。
クラス/構造体/共用体は、それが単純で、標準レイアウトであり、かつそのすべての非静的データメンバーと基底クラスがPODである場合にPODとみなされます。
これらの概念を分離することで、一方を放棄しても他方を失うことなく済むようになります。複雑なムーブコンストラクタとコピーコンストラクタを持つクラスは自明ではないかもしれませんが、標準レイアウトであればC言語と相互運用可能です。同様に、パブリックおよびプライベートの非静的データメンバを持つクラスは標準レイアウトではありませんが、自明であればC言語と相互memcpy運用可能です。
C++03では、翻訳単位内で完全指定テンプレートが検出されるたびに、コンパイラはテンプレートをインスタンス化する必要があります。複数の翻訳単位で同じ型でテンプレートがインスタンス化されると、コンパイル時間が大幅に増加する可能性があります。C++03ではこれを防ぐ方法がないため、C++11ではexternデータ宣言に類似したexternテンプレート宣言が導入されました。
C++03では、コンパイラにテンプレートをインスタンス化させるための構文として、以下のものが用意されています。
テンプレートクラスstd :: vector <X> ;C++11では、以下の構文が利用できるようになりました。
extern template class std :: vector < X > ;これは、コンパイラに対し、この翻訳単位内でテンプレートをインスタンス化しないように指示するものです。
これらの機能は、言語の使いやすさを向上させることを主な目的として存在します。これにより、型の安全性の向上、コードの重複の最小化、エラーコードの発生確率の低下などが可能になります。
C++03はCから初期化リスト機能を継承しました。構造体または配列には、構造体内のメンバの定義順に、中括弧で囲まれた引数リストが渡されます。これらの初期化リストは再帰的であるため、構造体の配列や、他の構造体を含む構造体でも使用できます。
struct FloatAndInt { float first ; int second ; };FloatAndInt scalar = { 0.43f , 10 }; // 1 つのオブジェクト (first=0.43f、second=10) FloatAndInt a [] = {{ 13.4f , 3 }, { 43.28f , 29 }, { 5.934f , 17 }}; // 3 つのオブジェクトの配列これは静的リストや構造体を何らかの値で初期化する場合に非常に便利です。C++ にはオブジェクトを初期化するためのコンストラクタもありますが、初期化リストほど便利ではない場合が多いです。ただし、C++03 では、初期化リストは Plain Old Data (POD) 定義に準拠する構造体とクラスでのみ使用できます。C++11 では初期化リストが拡張され、標準コンテナなどのすべてのクラスで使用できるようになりましたstd::vector<T>。
C++11 では、この概念は と呼ばれるテンプレートに結び付けられていますstd::initializer_list<T>。これにより、コンストラクタやその他の関数が初期化リストをパラメータとして受け取ることができます。例:
std :: initializer_listを使用します。class MySequence { public : MySequence ( initializer_list <int> list ) ; } ;これMySequenceにより、次のような整数のシーケンスから構築することが可能になります。
MySequence s = { 1 , 4 , 5 , 6 };このコンストラクタは、初期化リストコンストラクタと呼ばれる特殊なタイプのコンストラクタです。このようなコンストラクタを持つクラスは、統一初期化の際に特別な扱いを受けます(下記参照)。
テンプレートクラスは、C++11 標準ライブラリの第一級std::initializer_list<T>型です。このような中括弧が に推論されるコンテキストでは、型名のない構文を使用することで、 C++11 コンパイラによって静的に構築できます。また、 のように型を明示的に指定することもできます(他の構築構文についても同様です)。{}std::initializer_list<T>std::initializer_list<T>{args}
リストは構築後にコピーすることができ、これは低コストで参照によるコピーとして機能します(クラスは通常、開始ポインタと終了ポインタのペアとして実装されます)。 はstd::initializer_list<T>定数です。作成後にメンバーを変更することはできず、メンバー内のデータも変更できません(これにより、メンバーからの移動やクラスメンバーへのコピーなどが可能になります)。
コンパイラによってその構築は特別に処理されますが、 はstd::initializer_list<T>実際の型であるため、クラスコンストラクタ以外の場所でも使用できます。通常の関数は、型付き をstd::initializer_list<T>引数として受け取ることができます。例:
std :: initializer_listを使用します。void foo ( initializer_list < float > list ); // コピーは安価です。上記を参照してください。foo ({ 1.0f , -3.45f , -0.4f });標準ライブラリにおけるこの例としては、数値型の を受け取るテンプレートstd::min()やstd::max()テンプレートなどがあります。std::initializer_list<T>
標準コンテナは、以下の方法でも初期化できます。
using std :: string ; using std :: vector ;vector < string > v = { "xyzzy" , "plugh" , "abracadabra" }; vector < string > v ({ "xyzzy" , "plugh" , "abracadabra" }); vector < string > v { "xyzzy" , "plugh" , "abracadabra" }; // 下記の「Uniform initialization」を参照C++03 では、型の初期化に関して多くの問題があります。初期化を行う方法はいくつかあり、それらを組み合わせると異なる結果になるものもあります。たとえば、従来のコンストラクタ構文は関数宣言のように見えることがあり、コンパイラの最も厄介な構文解析ルールがそれを関数宣言と誤認しないように対策を講じる必要があります。集約型と POD 型のみが集約型初期化子 ( を使用) で初期化できます。Tx={/* initialization */};
C++11では、あらゆるオブジェクトで機能する、完全に統一された型初期化を可能にする構文が提供されています。これは、初期化子リスト構文を拡張したものです。
struct IntAndFloat1 { int x ; double y ; };struct IntAndFloat2 { private : int x ; double y ; public : IntAndFloat2 ( int x , double y ) : x { x }, y { y } {} };IntAndFloat1 v1 { 5 , 3.2 }; IntAndFloat2 v2 { 2 , 4.3 };の初期化は、v1集約初期化とまったく同じように動作します。つまり、オブジェクトの各データメンバは、初期化リストから対応する値で順番にコピー初期化されます。必要に応じて暗黙的な型変換が使用されます。変換が存在しない場合、または縮小変換のみが存在する場合は、プログラムは不正な形式です。 の初期化はv2コンストラクタを呼び出します。
次のような方法もあります。
std :: stringを使用します。struct IdString { string name ; int identifier ; };IdString getString () { return { "foo" , 42 }; // 明示的な型指定がないことに注意してください。}統一初期化はコンストラクタ構文を置き換えるものではなく、コンストラクタ構文は依然として必要な場合があります。クラスに初期化リストコンストラクタ()がある場合、初期化リストがシーケンスコンストラクタの型に準拠している限り、他の形式の構築よりも優先されます。C++11 バージョンのには、テンプレート型用の初期化リストコンストラクタがあります。したがって、次のコードになります。T(initializer_list<X>v);std::vector<T>
std :: vector <int> vec {4} ;初期化リストのコンストラクタが呼び出され、std::vector単一のサイズパラメータを受け取り、そのサイズのベクトルを作成するコンストラクタは呼び出されません。後者のコンストラクタにアクセスするには、標準のコンストラクタ構文を直接使用する必要があります。
C++03(およびC)では、変数を使用するには、その型を明示的に指定する必要があります。しかし、テンプレート型やテンプレートメタプログラミング技術の登場により、何かの型、特に明確に定義された関数の戻り値の型は、容易に表現できなくなりました。そのため、中間値を変数に格納することは難しく、場合によっては特定のメタプログラミングライブラリの内部構造に関する知識が必要になることがあります。
C++11 では、この問題を 2 つの方法で軽減できます。まず、明示的な初期化を持つ変数の定義にautoキーワードを使用できます。[ 12 ] [ 13 ]これにより、初期化子の特定の型の変数が作成されます。
std :: placeholders名前空間を使用します。auto callable = std :: bind ( & foo , _2 , _1 , x ); auto y = 5 ;の型は、特定の引数に対して のcallable特定のテンプレート関数オーバーライドがstd::bind()返す値に単純に等しくなります。この型は、コンパイラが意味解析の一環として手続き的に容易に決定できますが、ユーザーが目視で判断するのは容易ではありません。 の型yも明確に定義されていますが、ユーザーが判断するのは容易です。これは でありint、整数リテラルと同じ型です。
C++におけるこのキーワードの使用は、autoこのキーワードの意味を再利用するものであり、元々は型を持たない前身言語Bにおいて、型付けされていない自動変数定義を示すという関連する役割で使用されていた。
さらに、このキーワードはdecltypeコンパイル時に式の型を判定するために使用できます。例:
int i = 0 ; decltype ( i ) j = 5 ;autoこれは、自動変数の型がコンパイラのみに知られているため、と組み合わせるとより便利です。ただし、演算子オーバーロードdecltypeや特殊化された型を多用するコード内の式にも非常に役立ちます。
autoコードの冗長性を減らすのにも役立ちます。たとえば、次のように書く代わりに
std :: vectorを使用します。for ( vector < int >:: const_iterator it = v . cbegin (); it != v . cend (); ++ it ) { /* ループ */ }プログラマーはより短いものを使用できます
for ( auto it = v . cbegin (); it != v . cend (); ++ it ) { /* ループ */ }vこれは、実装begin()/end()イテレータによってさらにコンパクト化できます。
for ( const auto & x : v ) { /* ループ */ }プログラマがコンテナをネストし始めると、この差は大きくなりますが、そのような場合はtypedefコード量を減らすために s を使用することができます。
によって示される型は、decltypeによって推論される型とは異なる場合があるauto。
#include <vector>std :: vectorを使用します。int main () { const vector < int > v ( 1 ); auto a = v [ 0 ]; // a の型は int ですdecltype ( v [ 0 ]) b = 1 ; // b の型は const int& です。これはstd::vector<int>::operator[](size_type)の戻り値の型ですconst auto c = 0 ; // c の型は int ですauto d = c ; // d の型は int ですdecltype ( c ) e ; // e の型は int です。これは c で指定されたエンティティの型ですdecltype (( c )) f = c ; // f の型は int& です。これは (c) が左辺値であるためですdecltype ( 0 ) g ; // g の型は int です。これは 0 が右辺値であるためです}forC++11では、要素の範囲を簡単に反復処理できるように、ステートメントの構文が拡張されました。
int a [ 5 ] = { 1 , 2 , 3 , 4 , 5 }; // a の各要素の値を 2 倍にする: for ( int & x : a ) { x *= 2 ; }// 同様だが、配列要素の型推論も使用するfor ( auto & x : a ) { x *= 2 ; }この形式のforfor文は「範囲ベースfor」と呼ばれ、リスト内の各要素を反復処理します。Cスタイルの配列(コンパイル時に長さがわかっている場合)、初期化リスト、およびイテレータを返す関数が定義されている型であれば、どれでも使用できますbegin()。begin end()/endペアを持つすべての標準ライブラリコンテナは、範囲ベースfor文で動作します。
C++11では、ラムダ関数と呼ばれる匿名関数を作成する機能が提供されています。[ 14 ] これらは次のように定義されます。
// add という名前のラムダを定義します// 2 つの int を受け取り、int を返しますauto add = []( int x , int y ) -> int { return x + y ; }戻り値の型(この例では)は、すべての式が同じ型を返す限り省略できます。ラムダ式は、オプションでクロージャにすることもできます。->intreturn
標準C言語の関数宣言構文は、C言語の機能セットに対して十分でした。C++はC言語から進化する過程で、基本的な構文を維持しつつ、必要に応じて拡張しました。しかし、C++が複雑化するにつれて、特にテンプレート関数宣言に関して、いくつかの制限が明らかになりました。例えば、C++03では、これは無効です。
template < class L , class R > Ret add ( const L & lhs , const R & rhs ) { return lhs + rhs ; // Ret は lhs + rhs の型でなければならない}型は、型とRet型の加算によって生成される型になります。前述のC++11の機能を使用しても、これは不可能です。LRdecltype
// 無効な C++11テンプレート< class L , class R > decltype ( lhs + rhs ) add ( const L & lhs , const R & rhs ) { return lhs + rhs ; }これは有効な C++ ではありません。なぜならlhs、とrhsがまだ定義されていないからです。これらは、パーサーが関数プロトタイプの残りの部分を解析するまで、有効な識別子にはなりません。
これを回避するため、C++11 では末尾に戻り値の型を指定する新しい関数宣言構文が導入されました。[ 15 ]
template < class L , class R > auto add ( const L & lhs , const R & rhs ) -> decltype ( lhs + rhs ) { return lhs + rhs ; }この構文は、より一般的な関数宣言や定義に使用できます。
struct X { static auto add ( int x , int y ) -> int { return x + y ; } };この場合の「 」キーワードの使用はauto構文の一部にすぎず、C++11 では自動的な型推論は行われません。しかし、C++14 以降では、末尾の戻り値の型を完全に削除することができ、コンパイラが戻り値の型を自動的に推論します。[ 16 ]
C++03では、クラスのコンストラクタは、そのクラスの初期化リストにある他のコンストラクタを呼び出すことはできません。各コンストラクタは、クラスメンバーをすべて自身で構築するか、共通のメンバー関数を呼び出す必要があります。以下にその例を示します。
class Integer { private : int value ;void setValue ( int num ) { value = num ; } public : Integer ( int number ) { setValue ( number ); }整数() { setValue ( 42 ); } };基底クラスのコンストラクタは派生クラスに直接公開することはできません。基底クラスのコンストラクタが適切な場合でも、各派生クラスはコンストラクタを実装する必要があります。クラスの非定数データメンバは、そのメンバの宣言箇所で初期化することはできません。初期化はコンストラクタ内でのみ可能です。
C++11は、これらの問題すべてに対する解決策を提供します。
C++11では、コンストラクタが他のピアコンストラクタを呼び出すことができるようになりました(これを委譲と呼びます)。これにより、コンストラクタは最小限のコード追加で他のコンストラクタの動作を利用できるようになります。委譲は、 JavaやObjective-Cなどの他の言語でも使用されています。
構文は以下のとおりです。
class Integer { private : int value ; public : Integer ( int number ) : value ( number ) {}整数() :整数( 42 ) {} };この場合、デフォルトパラメータを設定することで同じ効果を得ることができましたnumber。しかし、新しい構文では、デフォルト値(42)をインターフェースではなく実装で表現できます。これは、関数パラメータのデフォルト値が呼び出し箇所に「組み込まれている」のに対し、コンストラクタ委譲ではライブラリを使用するコードを再コンパイルすることなく値を変更できるため、ライブラリコードの保守担当者にとってメリットとなります。
ただし、注意点があります。C++03 では、コンストラクタの実行が完了した時点でオブジェクトが構築されたとみなされますが、C++11 では、いずれかのコンストラクタの実行が完了した時点でオブジェクトが構築されたとみなされます。複数のコンストラクタの実行が許可されるため、各委譲コンストラクタは、自身の型の完全に構築されたオブジェクトに対して実行されることになります。派生クラスのコンストラクタは、基底クラスにおけるすべての委譲が完了した後に実行されます。
基底クラスのコンストラクタに関して、C++11 では、クラスが基底クラスのコンストラクタを継承するように指定できます。そのため、C++11 コンパイラは、継承を実行し、派生クラスから基底クラスへの転送を行うコードを生成します。これは、すべてかゼロかの機能です。つまり、基底クラスのコンストラクタはすべて転送されるか、まったく転送されないかのどちらかです。また、継承されたコンストラクタが派生クラスのコンストラクタのシグネチャと一致する場合、そのコンストラクタはシャドウイングされます。多重継承には制限があり、同じシグネチャを持つコンストラクタを使用する 2 つのクラスからクラスコンストラクタを継承することはできません。
構文は以下のとおりです。
class Base { public : Base ( int value ); };class Derived : public Base { public : using Base :: Base ; };メンバーの初期化には、C++11では次の構文が使用できます。
class Integer { private : int value = 5 ; public : Integer () {}explicit Integer ( int value ) : value ( value ) {} };クラスのコンストラクタは、value独自の初期化処理で初期化を上書きしない限り、すべて5で初期化されます。したがって、上記の空のコンストラクタはvalueクラス定義に従って初期化されますが、int型を受け取るコンストラクタは、指定されたパラメータで初期化されます。
また、上記に示した代入初期化の代わりに、コンストラクタ初期化または統一初期化を使用することもできます。
C++03では、基底クラスの関数をオーバーライドしようとした際に、誤って新しい仮想関数を作成してしまう可能性があります。例えば、次のようになります。
struct Base { virtual void foo ( float x ); };struct Derived : public Base { virtual void foo ( int x ); };仮に、この関数が基底クラスのバージョンを置き換えることを意図していたとします。しかし、シグネチャDerived::foo()が異なるため、2つ目の仮想関数が作成されてしまいます。これは、特にユーザーが基底クラスを変更しようとする際によく発生する問題です。
C++11には、この問題を解決するための構文が用意されています。
struct Base { virtual void foo ( float x ); };struct Derived : public Base { virtual void foo ( int x ) override ; // 不正な形式 - 基底クラスのメソッドをオーバーライドしていません};このoverride特別な識別子は、コンパイラが基底クラスをチェックし、このシグネチャと完全に一致する仮想関数が存在するかどうかを確認することを意味します。存在しない場合は、コンパイラはエラーを通知します。
C++11では、クラスからの継承を禁止したり、派生クラスでのメソッドのオーバーライドを単純に禁止したりする機能も追加されました。これは、特別な識別子を使用して行いますfinal。例:
struct Base final { // ... };// クラス Base が final とマークされているため、形式が正しくありませんstruct Derived : public Base { // ... };struct Base { virtual void foo () final ; };struct Derived : public Base { void foo (); // 仮想関数 Base::foo が final とマークされているため、不正な形式です};この例では、virtual void foo() final;ステートメントは新しい仮想関数を宣言していますが、派生クラスによるオーバーライドも禁止しています。また、派生クラスがその特定の関数名とパラメータの組み合わせを使用することも禁止する効果があります。
どちらも言語キーワードでoverrideはありませんfinal。これらは厳密には宣言子属性の識別子です。
このセクションの目的上、そしてこのセクションのみにおいて、「0」という表記はすべて「 に評価される定数式であり0、型は int である」という意味で使用されます。実際には、定数式は任意の整数型であっても構いません。
1972年のC言語の黎明期以来、定数は0定数整数とヌルポインタ定数という二重の役割を担ってきました。この二重の意味に内在する曖昧さは、0C言語ではプリプロセッサマクロを使用することで対処されNULL、これは通常、またはに展開されます。C ++ではから他のポインタ型への暗黙的な変換が禁止されているため、へのキャストの利点が失われます。結果として、ヌルポインタ定数として許可されるのはのみとなります。これは関数オーバーロードとうまく連携しません。((void*)0)0void*0void*0
void foo ( char * s ); void foo ( int i );NULLが と定義されている場合0(これは通常 C++ の場合です)、ステートメントはを呼び出しますが、これはプログラマーが意図したものではなく、コードを表面的に読んだだけでは示唆されることでもありません。foo(NULL);foo(inti)
C++11 では、区別されたヌルポインタ定数として機能する新しいキーワード を導入することで、この問題を修正していますnullptr。 は 型でありnullptr_t、任意のポインタ型またはメンバへのポインタ型と暗黙的に変換可能で比較可能です。 は、 を除いて、整数型とは暗黙的に変換可能でも比較可能でもありませんbool。 当初の提案では、 型の右辺値はnullptr_tに変換できないようboolに指定されていましたが、コア言語ワーキンググループは、通常のポインタ型との一貫性を保つために、そのような変換が望ましいと判断しました。提案された文言の変更は、2008 年 6 月にワーキング ペーパーに満場一致で採択されました。同様の提案はC標準ワーキンググループにも提出され、C23への組み込みが承認された。[ 17 ]
後方互換性の理由から、0有効なヌルポインタ定数として保持されます。
char * pc = nullptr ; // OK int * pi = nullptr ; // OK bool b = nullptr ; // OK。b は false です。int i = nullptr ; // エラーfoo ( nullptr ); // foo(int i); ではなく foo(nullptr_t p) を呼び出します。/* 上記の例では、foo(nullptr_t p) は、 スコープ内で互換性のあるポインタ型でオーバーロードされている他の関数がない場合に限り、暗黙的な型変換を使用して実際に foo(char* s) を呼び出します。複数のオーバーロードが存在する場合、 foo(nullptr_t p) の明示的な宣言がない限り 、曖昧であるため解決は失敗します。 C++11 の標準型ヘッダーでは、nullptr_t 型は次のように宣言する必要があります。 using nullptr_t = decltype(nullptr); ただし、次のようには宣言しないでください。 using nullptr_t = int; // NULL を 0 として定義する必要がある以前のバージョンの C++ using nullptr_t = void*; // NULL を ((void*)0) */ として定義する ANSI CC++03 では、列挙型は型安全ではありません。列挙型が異なっていても、実質的には整数として扱われます。これにより、異なる列挙型の 2 つの列挙値を比較することが可能になります。C++03 が提供する唯一の安全対策は、整数またはある列挙型の値が、別の列挙型に暗黙的に変換されないことです。さらに、基となる整数型は実装依存であるため、列挙型のサイズに依存するコードは移植性がありません。最後に、列挙値は囲んでいるスコープに限定されます。したがって、同じスコープ内の 2 つの異なる列挙型が、同じメンバ名を持つことはできません。
C++11では、これらの問題が一切ない特別な列挙型の分類が認められています。これは、enum class(enum structも同義語として認められます) 宣言を使用して表現されます。
enum class CardSuit { CLUBS = 1 , HEARTS = 2 , DIAMONDS = 4 , SPADES = 8 };この列挙型は型安全です。列挙型クラスの値は暗黙的に整数に変換されません。したがって、整数と比較することもできません(この式はコンパイルエラーになります)。CardSuit::SPADES==8
列挙型クラスの基となる型は常に既知です。デフォルトの型は ですがint、次の例に示すように、別の整数型にオーバーライドできます。
enum class Direction : char { UP , DOWN , LEFT , RIGHT };旧式の列挙型では、値は外側のスコープに配置されます。新式の列挙型では、値は列挙型クラス名のスコープ内に配置されます。したがって、上記の例では、UPは未定義ですが、Direction::UPは定義されています。
また、旧式の列挙型で明示的なスコープと基となる型の定義を可能にするための移行構文も存在します。
enum Direction : char { UP , DOWN , LEFT , RIGHT };この場合、列挙子名は列挙のスコープ(Direction::UP)で定義されますが、後方互換性のために、それらを囲むスコープにも配置されます。
C++11では、列挙型の前方宣言も可能になりました。以前は、列挙型のサイズがメンバーの定義に依存するため、列挙型を前方宣言することはできませんでした。列挙型のサイズが暗黙的または明示的に指定されていれば、前方宣言が可能になります。
enum Enum1 ; // C++03 および C++11 では無効です。基となる型を判別できません。enum Enum2 : unsigned int ; // C++11 では有効です。基となる型が明示的に指定されています。enum class Enum3 ; // C++11 では有効です。基となる型は int です。enum class Enum4 : unsigned int ; // C++11 では有効です。enum Enum2 : unsigned short ; // C++11 では無効です。Enum2 は以前に別の基となる型で宣言されていたためです。C++03のパーサーは、「」をあらゆる場合において右シフト演算子またはストリーム抽出演算子として定義します。しかし、ネストされたテンプレート宣言では、プログラマが2つの右山括弧の間にスペースを入れるのを忘れがちで、その結果コンパイラの構文エラーが発生します。>>
C++11 では、パーサーの仕様が改善され、複数の右山括弧が適切な場合にはテンプレート引数リストを閉じるものとして解釈されるようになりました。これは、「>」、「>=」または「」の二項演算子を使用してパラメータ式を括弧で囲むことで上書きできます。>>
std :: vectorを使用します。template < bool Test > class X ; vector < X < 1 > 2 >> x1 ; // X<true> の std::vector として解釈され、// その後に "2 >> x1" が続きますが、これは宣言子として有効な構文ではありません。 1 は true です。vector < X < ( 1 > 2 ) >> x1 ; // これは、X<false> の std::vector として解釈され、// その後に宣言子 "x1" が続きます。これは有効な C++11 構文です。(1>2) は false です。C++98 では、explicit単一引数コンストラクタが暗黙的な型変換演算子として使用されないように、コンストラクタの修飾子としてキーワードが追加されました。しかし、これは実際の変換演算子には影響しません。たとえば、スマートポインタクラスは、プリミティブポインタのように動作できるようにすることができます。この変換が含まれている場合、(ポインタが null でない場合は true、それ以外の場合は false になります) でテストできます。ただし、これにより、意図しない他の変換も許可されます。C++ は算術型として定義されているため、暗黙的に整数型や浮動小数点型に変換される可能性があり、ユーザーが意図していない数学演算が可能になります。operatorbool()if(p)bool
C++11では、explicitキーワードを型変換演算子にも適用できるようになりました。コンストラクタと同様に、暗黙的な型変換でこれらの変換関数を使用することを防ぎます。ただし、ブール値が必要な言語コンテキスト(if文やループの条件、論理演算子のオペランドなど)は明示的な型変換とみなされ、bool型変換演算子を使用できます。
例えば、この機能は安全なブール値の問題を明確に解決します。
C++03では、typedefは他の型の同義語としてのみ定義できます。これには、実際のテンプレート引数をすべて指定したテンプレート特殊化の同義語も含まれます。typedefテンプレートを作成することはできません。例:
テンプレート< typename First , typename Second , int Third >クラスX ;template < typename Second > typedef X < A , Second , 5 > Y ; // C++03 では無効これはコンパイルできません。
C++11では、以下の構文でこの機能が追加されました。
テンプレート< typename First , typename Second , int Third >クラスX ;テンプレート< typename Second > using Y = X < A , Second , 5 > ;このusing構文は、C++11 では型エイリアスとしても使用できます。
typedef void ( * FunctionType )( double ); // 旧スタイル:FunctionType = void ( * )( double ); // 新しく導入された構文C++03では、共用体のメンバーになり得るオブジェクトの型に制限がありましたunion。例えば、共用体には、非自明なコンストラクタやデストラクタを定義するオブジェクトを含めることはできませんでした。C++11では、これらの制限の一部が解除されています。
unionメンバーに非自明な特殊メンバー関数がある場合、コンパイラはそれに対応するメンバー関数を生成しないため、union手動で定義する必要があります。
これは、C++11で許可されている共用体の簡単な例です。
#include <new> // 'new' を配置するために必要です。struct Point { int a ; int b ;Point () {} Point ( int x , int y ) : x ( a ), y ( b ) {} };union MyUnion { int z ; double w ; Point p ; // C++03 では無効。C++11 では有効。// Point メンバーのため、コンストラクタ定義が必要になりました。MyUnion () {}MyUnion ( const Point & pt ) : p ( pt ) {} // 初期化リストを使用して Point オブジェクトを構築します。MyUnion & operator = ( const Point & pt ) { // 配置 'new' を使用して Point オブジェクトを割り当てます。new ( & p ) Point ( pt ); return * this ; } };今回の変更は既存の規則を緩和するだけなので、既存のコードに支障をきたすことはありません。
これらの機能により、以前は不可能だったこと、非常に冗長だったこと、あるいは移植性のないライブラリが必要だったことが、この言語で可能になる。
C++11では、テンプレートは可変個のテンプレートパラメータを受け取ることができます。これにより、型安全な可変引数関数を定義することも可能になります。
C++03 では、2 種類の文字列リテラルが提供されています。1 種類目は二重引用符で囲まれ、型のヌル終端配列を生成しますconst char。2 種類目はとして定義されL""、型ヌル終端配列を生成します。const wchar_tここで、はサイズと意味が未定義のワイド文字です。どちらのリテラル型も、UTF-8、UTF-16、またはその他のUnicodeエンコーディングwchar_tの文字列リテラルをサポートしていません。
C++11 は、UTF-8、UTF-16、UTF-32 の3 つの Unicode エンコーディングをサポートしています。型の定義がchar変更され、UTF-8 の 8 ビット コーディングを格納するのに必要なサイズ以上であり、コンパイラの基本実行文字セットの任意のメンバーを格納できる大きさであることが明示的に表現されるようになりました。以前は、C++ 標準自体では後者のみとして定義されており、少なくとも 8 ビットを保証するために C 標準に依存していました。さらに、C++11 では と という 2 つの新しい文字型が追加されましたchar16_t。char32_tこれらはそれぞれ UTF-16 と UTF-32 を格納するように設計されています。
サポートされている各エンコーディングに対応する文字列リテラルは、次のように作成できます。
u8 "私はUTF-8文字列です。" u "これはUTF-16文字列です。" U "これはUTF-32文字列です。"最初の文字列の型は通常の ですconst char[]。2 番目の文字列の型はconst char16_t[](小文字の 'u' 接頭辞に注意) です。3 番目の文字列の型はconst char32_t[](大文字の 'U' 接頭辞) です。
Unicode文字列リテラルを作成する際、Unicodeコードポイントを文字列に直接挿入すると便利な場合がよくあります。C++11では、これを行うために次の構文が使用できます。
u8 "これはUnicode文字です: \u2018 。" u "これはより大きなUnicode文字です: \u2018 。" U "これはUnicode文字です: \U00002018 。"の後の数字\uは16進数です。通常の接頭辞は必要ありません0x。識別子は\u16ビットのUnicodeコードポイントを表します。32ビットのコードポイントを入力するには、\Uと32ビットの16進数を使用します。有効なUnicodeコードポイントのみを入力できます。たとえば、U+D800~U+DFFFの範囲のコードポイントは、UTF-16エンコーディングのサロゲートペア用に予約されているため、使用できません。
特にXMLファイル、スクリプト言語、正規表現のリテラルを使用する場合、文字列を手動でエスケープすることを避ける方が便利な場合もあります。C++11では、生の文字列リテラルが提供されています。
R " (文字列データ\ 何か " ) " R "区切り文字 (文字列データ\ 何か " )区切り文字"最初のケースでは、"(との間のすべてが)"文字列の一部です。"と\文字はエスケープする必要はありません。2 番目のケースでは、が"delimiter(文字列の開始であり、)delimiter"に到達したときにのみ終了します。文字列はdelimiter、空文字列を含めて、最大 16 文字の長さの任意の文字列にすることができます。この文字列には、スペース、制御文字、、、または文字を含めることはできません(。)この\区切り文字列を使用すると、ユーザーは)"生の文字列リテラル内にシーケンスを含めることができます。たとえば、はと同等です。R"delimiter("(a-z)")delimiter""\"(a-z)\""
生の文字列リテラルは、ワイドリテラルまたはUnicodeリテラルの接頭辞のいずれかと組み合わせることができます。
u8R " XXX(私は「生の UTF-8」文字列です。)XXX " uR " *(これは「生の UTF-16」文字列です。)* " UR " (これは「生の UTF-32」文字列です。) "C++03 では、いくつかのリテラルが提供されています。文字は12.5リテラルであり、コンパイラによってdouble値 12.5 を持つ型として解決されます。ただし、fのようにサフィックスを追加すると、値 12.5 を含む12.5f型の値が作成されますfloat。リテラルのサフィックス修飾子は C++ 仕様で固定されており、C++03 コードでは新しいリテラル修飾子を作成することはできません。
それに対し、C++11では、リテラルが修飾する文字列に基づいてオブジェクトを構築する、新しい種類のリテラル修飾子をユーザーが定義できるようになった。
リテラルの変換は、生の段階と加工済みの段階の 2 つの明確な段階に再定義されます。生のリテラルは特定の型の文字のシーケンスであり、加工済みのリテラルは別の型です。C++ リテラル は1234、生のリテラルとしては、文字のシーケンス'1'、'2'、'3'、'4'です。加工済みのリテラルとしては、整数 1234 です。C++ リテラルは、0xA生の形式では'0'、'x'、'A'であり、加工済みの形式では整数 10 です。
リテラルは、生の形式と処理済みの形式の両方で拡張できますが、文字列リテラルは例外で、処理済みの形式でのみ処理できます。この例外は、文字列には、対象となる文字の特定の意味と型に影響を与える接頭辞があるためです。
ユーザー定義リテラルはすべて接尾辞であり、接頭辞リテラルを定義することはできません。アンダースコア(_)以外の文字で始まるすべての接尾辞は標準で予約されています。したがって、すべてのユーザー定義リテラルはアンダースコア(_)で始まる接尾辞を持つ必要があります。[ 18 ]
リテラルの生の形式を処理するユーザー定義リテラルは、リテラル演算子を介して定義され、それは と記述されますoperator""。例を以下に示します。
MyOutput演算子"" _suf ( const char * s ) { // MyOutput には const char* MyOutputを受け取るコンストラクタがあると仮定しますret ( s ); return ret ; }MyOutput x = 1234 _suf ; // MyOutput には double を返す value() メソッドがあると仮定しますassert ( x . value () == 1234.0 )代入文は、ユーザー定義リテラル関数で定義されたコードを実行します。この関数はCスタイルの文字列として渡されるため、ヌル終端文字を持ちます。MyOutputx=1234_suf;"1234"
整数および浮動小数点の生リテラルを処理するための別のメカニズムとして、可変引数テンプレートを使用する方法があります。
テンプレート< char ... _ > MyOutput演算子"" _suf ();MyOutput x = 1234 _suf ; MyOutput y = 2.17 _suf ;これは、リテラル処理関数を としてインスタンス化します。この形式では、文字列を終端するヌル文字はありません。これを行う主な目的は、C++11 のキーワードを使用して、 がconstexpr で構築可能かつコピー可能な型であり、リテラル処理関数が関数であると仮定して、コンパイラがコンパイル時にリテラルを完全に変換することを保証することです。operator""_suf<'1','2','3','4'>()constexprMyOutputconstexpr
数値リテラルの場合、クックされたリテラルの型は、unsigned long long整数リテラル用かlong double浮動小数点リテラル用のいずれかです。(注:符号付き整数型は必要ありません。符号付きリテラルは、符号を単項接頭辞演算子として含む式と符号なし数値として解析されるためです。)代替のテンプレート形式はありません。
MyOutput operator "" _suf ( unsigned long long ); MyOutput operator "" _suf ( long double );MyOutput x = 1234 _suf ; // 'unsigned long long' オーバーロードを使用します。MyOutput y = 3.1416 _suf ; // 'long double' オーバーロードを使用します。先に述べた新しい文字列接頭辞に従い、文字列リテラルには以下の接頭辞が使用されます。
MyOutput operator "" _suf ( const char * s , size_t length ); MyOutput operator "" _suf ( const wchar_t * s , size_t length ); MyOutput operator "" _suf ( const char16_t * s , size_t length ); MyOutput operator "" _suf ( const char32_t * s , size_t length );MyOutput a = "1234" _suf ; // 'const char*' オーバーロードを使用します。MyOutput b = u8 "1234" _suf ; // 'const char*' オーバーロードを使用します。MyOutput c = L "1234" _suf ; // 'const wchar_t*' オーバーロードを使用します。MyOutput d = u "1234" _suf ; // 'const char16_t*' オーバーロードを使用します。MyOutput e = U "1234" _suf ; // 'const char32_t*' オーバーロードを使用します。代替のテンプレート形式はありません。文字リテラルも同様に定義されます。
C++11はマルチスレッドプログラミングのサポートを標準化しています。
これには2つの要素が関係しています。1つは、プログラム内で複数のスレッドが共存できるようにするメモリモデル、もう1つは、スレッド間の相互作用をサポートするライブラリです。(スレッド機能に関するこの記事のセクションを参照してください。)
メモリモデルは、複数のスレッドが同じメモリ位置にアクセスできるタイミングを定義し、あるスレッドによる更新が他のスレッドから見えるようになるタイミングを指定します。
マルチスレッド環境では、各スレッドが固有の変数を持つことが一般的です。これは関数のローカル変数では既に実現されていますが、グローバル変数や静的変数では実現されていません。
スレッドローカルストレージの新しい期間(既存のstatic、dynamic、automaticに加えて)は、storage 指定子によって示されますthread_local。
静的ストレージ期間(つまり、プログラムの実行期間全体にわたる有効期間)を持つ可能性のあるオブジェクトには、代わりにスレッドローカル期間を割り当てることができます。これは、他の静的期間変数と同様に、スレッドローカルオブジェクトをコンストラクタで初期化し、デストラクタで破棄できるようにするためです。
C++03では、コンパイラは、デフォルトコンストラクタ、コピーコンストラクタ、コピー代入演算子(operator=)、およびデストラクタを、クラス自身で提供しない場合に提供します。プログラマは、カスタムバージョンを定義することで、これらのデフォルトをオーバーライドできます。C++はまた、すべてのクラスで機能するいくつかのグローバル演算子(などoperator new)を定義しており、プログラマはこれらをオーバーライドできます。
しかし、これらのデフォルトを作成する際の制御は非常に限られています。たとえば、プライベートなコピーコンストラクタとコピー代入演算子を宣言し、それらを定義しないことで、クラスを本質的にコピー不可にすることができます。これらの関数を使用しようとすると、単一定義ルール(ODR)に違反します。診断メッセージは必須ではありませんが、[ 19 ]違反するとリンカエラーが発生する可能性があります。
デフォルトコンストラクタの場合、クラスがコンストラクタで定義されていると、コンパイラはデフォルトコンストラクタを生成しません。これは多くの場合便利ですが、特殊なコンストラクタとコンパイラが生成するデフォルトコンストラクタの両方を使用できることも便利です。
C++11では、これらの特殊なメンバ関数の明示的なデフォルト値の設定と削除が可能です。[ 20 ]例えば、このクラスはデフォルトコンストラクタが使用できることを明示的に宣言しています。
class X { X () = default ; // デフォルトコンストラクタが明示的に指定されています。X ( T value ); };関数は明示的に無効にすることができます。これは暗黙的な型変換を防ぐのに役立ちます。= delete指定子を使用すると、特定のパラメータ型を持つ関数の呼び出しを禁止できます。[ 20 ]例:
void noInt ( double i ); void noInt ( int ) = delete ;noInt()パラメータを指定して呼び出そうとするとint、コンパイラは暗黙的に への変換を行う代わりに、それを拒否しますdouble。 をnoInt()指定して呼び出すことはfloat引き続き機能します。
doubleテンプレートを使用することで、特定の型以外の型で関数を呼び出すことを禁止することが可能です。
double onlyDouble ( double d ) { return d ; }template < typename T > double onlyDouble ( T ) = delete ;呼び出しはonlyDouble(1.0)機能しますが、onlyDouble(1.0f)呼び出しはコンパイラエラーを生成します。
クラスメンバ関数とコンストラクタも削除できます。たとえば、コピーコンストラクタと以下のコードを削除することで、クラスオブジェクトのコピーを防ぐことができますoperator =。
class NonCopyable { NonCopyable (); NonCopyable ( const NonCopyable & ) = delete ; NonCopyable & operator = ( const NonCopyable & ) = delete ; };long long intC++03 では、最大の整数型は ですlong int。 は と同等以上の使用可能なビット数を持つことが保証されていますint。このため、long int一般的な実装では のサイズが 64 ビット、他の実装では 32 ビットになるという結果になりました。C++11 では、long long intこの問題を解決するために新しい整数型が追加されました。 は と同等以上のサイズであることが保証されlong int、64 ビット以上を持つことが保証されています。 型は元々C99で標準 C に導入され、ほとんどの C++ コンパイラは既に拡張としてサポートしていました。[ 21 ] [ 22 ]
C++03では、アサーションをテストする方法としてマクロassertとプリプロセッサディレクティブの2つが提供されています#error。しかし、どちらもテンプレートでの使用には適していません。マクロは実行時にアサーションをテストするのに対し、プリプロセッサディレクティブはテンプレートのインスタンス化前に行われるプリプロセス中にアサーションをテストするからです。また、どちらもテンプレートパラメータに依存するプロパティのテストには適していません。
この新しいユーティリティは、新しいキーワードを使用してコンパイル時にアサーションをテストする新しい方法を導入しますstatic_assert。宣言は次の形式をとります。
static_assert(定数式、エラーメッセージ);
以下に、static_assert使用例をいくつか示します。
static_assert (( GREEK_PI > 3.14 ) && ( GREEK_PI < 3.15 ), "GREEK_PIが不正確です!" );template < class T > struct Check { static_assert ( sizeof ( int ) <= sizeof ( T ), "T は十分な大きさではありません!" ); };std :: is_integralを使用します。template < class Int > Int foo ( Int x , Int y ) { static_assert ( is_integral < Int >:: value , "foo() のパラメータは整数型でなければなりません。" ); }定数式が の場合、falseコンパイラはエラー メッセージを生成します。最初の例はプリプロセッサ ディレクティブ に似ています#errorが、プリプロセッサは整数型のみをサポートしています。[ 23 ]対照的に、2 番目の例では、アサーションはテンプレート クラス のインスタンス化ごとにチェックされますCheck。
静的アサーションはテンプレート以外でも役立ちます。たとえば、アルゴリズムの特定の実装では、のサイズがlong longよりも大きいことが前提となる場合がありますintが、これは標準では保証されていません。このような前提はほとんどのシステムとコンパイラで有効ですが、すべてではありません。
sizeof明示的なオブジェクトなしでクラスのメンバーを操作することを許可するC++03では、sizeof演算子は型とオブジェクトに対して使用できます。ただし、次のような操作には使用できません。
struct X { Tメンバー; };sizeof ( X :: member ); // C++03では動作しません。C++11では動作します。これは のサイズを返すはずですT。C++03 ではこれが許可されていないため、コンパイルエラーになります。C++11 では許可されています。また、alignofC++11 で導入された演算子でも許可されています。
alignofC++11 では、変数のアライメントを とで照会および制御できますalignas。
このalignof演算子は型を受け取り、型インスタンスを割り当てる必要があるバイト境界の 2 乗の値を返します ( としてstd::size_t)。参照型が指定された場合はalignof、参照先の型の配置を返します。配列の場合は、要素型の配置を返します。
指定子alignasは変数のメモリ配置を制御します。指定子は定数または型を受け取ります。型が指定された場合、 の省略形となります。たとえば、が を格納するために適切に配置されるように指定するには、次のようにします。alignas(T)alignas(alignof(T))char[]float
alignas ( float ) unsigned char c [ sizeof ( float )];以前の C++ 標準では、プログラマ主導のガベージ コレクションが規定されていましたが、自動ガベージ コレクションの目的でオブジェクト到達可能性の定義は提供されていませんでした。C++11 では、ポインタ値が他の値から「安全に導出される」条件が定義されています。実装によっては、厳密なポインタ安全性の下で動作するように指定することができ、その場合、これらの規則に従って導出されていないポインタは無効になる可能性があります。これは後にC++23で削除されました。[ 24 ]
C++11では、コンパイラやツールによる言語拡張のための標準化された構文が提供されています。従来、このような拡張は#pragmaディレクティブやベンダー固有のキーワード(__attribute__GNUや__declspecMicrosoftなど)を使用して指定されていました。新しい構文では、追加情報を二重角括弧で囲まれた属性の形式で指定できます。属性は、ソースコードのさまざまな要素に適用できます。
int [[ attr1 ]] i [[ attr2 , attr3 ]];[[ attr4 ( arg1 , arg2 )]] if ( cond ) { [[ vendor :: attr5 ]] return i ; }上記の例では、属性は変数の型に適用され、は変数自体に適用され、はステートメントに適用され、は戻り値ステートメントに適用されます。一般的に(ただしいくつかの例外あり)、名前付きエンティティに指定された属性は名前の後に配置され、それ以外の場合は、上記のように、1組の二重角括弧内に複数の属性をリストすることができ、属性に追加の引数を指定でき、属性はベンダー固有の属性名前空間によってスコープすることができます。[[attr1]]i[[attr2]][[attr3]][[attr4]]if[[vendor::attr5]]
属性は言語的な意味を持たず、無視してもプログラムの意味が変わらないことが推奨されます。属性は、例えばコンパイラがより適切な診断情報を出力したり、生成されるコードを最適化したりするのに役立つ情報を提供する場合に役立ちます。
C++11自体が2つの標準属性を提供しています。1つは関数が値を返さないことを指定する属性、もう1つは関数の引数または戻り値が依存関係を持つことを示すことでマルチスレッドコードの最適化を支援する属性です。[[noreturn]][[carries_dependency]]
C++11標準ライブラリには、多くの新機能が導入されました。これらの機能の多くは旧規格でも実装可能でしたが、一部は(程度の差こそあれ)C++11のコア機能に依存しています。
新しいライブラリの大部分は、2005 年に発行されたC++ 標準委員会のライブラリ技術レポート(TR1 と呼ばれる)文書で定義されました。現在、TR1 のさまざまな完全実装および部分実装が名前空間を使用して利用可能ですstd::tr1。C++11 では、これらは名前空間に移動されましたstd。ただし、TR1 の機能が C++11 標準ライブラリに取り込まれるにつれて、最初の TR1 バージョンでは利用できなかった C++11 言語機能で適切にアップグレードされました。また、C++03 では可能だったものの、元の TR1 仕様には含まれていなかった機能で拡張された場合もあります。
C++11では、既存の標準ライブラリコンポーネントが活用できる多くの新しい言語機能が提供されています。例えば、ほとんどの標準ライブラリコンテナは、右辺値参照に基づくムーブコンストラクタのサポートを利用できます。これは、重いコンテナを素早く移動したり、コンテナの内容を新しいメモリ位置に移動したりする際に役立ちます。標準ライブラリコンポーネントは、必要に応じてC++11の新しい言語機能でアップグレードされました。これには、以下のような機能が含まれますが、これらに限定されるものではありません。
decltypeexplicit変換演算子さらに、前回のC++標準から長い年月が経過し、標準ライブラリを使用したコードが数多く記述されてきました。その結果、標準ライブラリの中には改善の余地がある部分が明らかになりました。改善が検討された多くの分野の中でも、標準ライブラリのアロケータは特に注目されました。C++11では、従来のモデルを補完する新しいスコープベースのアロケータモデルが導入されました。
C++03言語はスレッド処理をサポートするメモリモデルを提供していますが、実際にスレッド処理を使用するための主要なサポートはC++11標準ライブラリによって提供されます。
スレッドクラス(std::thread)が提供され、新しいスレッドで実行する関数オブジェクト(およびそれに渡すオプションの引数)を受け取ります。メンバ関数を介してスレッド結合をサポートするため、別の実行中のスレッドが完了するまでスレッドを停止させることができます。メンバ関数により、可能な場合は、プラットフォーム固有の操作std::thread::join()のために、基となるネイティブスレッドオブジェクトへのアクセスが提供されます。std::thread::native_handle()
スレッド間の同期のために、適切なミューテックス(std::mutex、std::recursive_mutexなど)と条件変数(std::condition_variableおよびstd::condition_variable_any)がライブラリに追加されています。これらは、リソース取得初期化(RAII)ロック(std::lock_guardおよびstd::unique_lock)とロックアルゴリズムを介して簡単にアクセスできます。
高性能かつ低レベルの処理においては、ミューテックスのオーバーヘッドなしにスレッド間の通信が必要となる場合があります。これは、メモリ位置に対するアトミック操作によって実現されます。これらの操作では、オプションで操作に必要な最小限のメモリ可視性制約を指定できます。また、明示的なメモリバリアをこの目的に使用することも可能です。
C++11 スレッドライブラリには、スレッド間で非同期の結果を渡すため、また、そのような非同期の結果を生成する可能性のある関数呼び出しをラップするためのfutures と promises もstd::packaged_task含まれています。futures の提案は、futures を組み合わせたり、一連の promises 内の 1 つの promise の完了をチェックする方法がないという理由で批判されました。[ 25 ]
スレッドプールなどの高度なスレッド機能については、今後のC++技術レポートで取り上げられる予定です。これらはC++11には含まれていませんが、最終的な実装はスレッドライブラリの機能に基づいて構築される見込みです。
この新しいstd::async機能により、タスクを実行してそれをに関連付ける便利な方法が提供されますstd::future。ユーザーは、タスクを別のスレッドで非同期に実行するか、値を待機するスレッドで同期的に実行するかを選択できます。デフォルトでは、実装はを選択でき、これにより、オーバーサブスクリプションなしでハードウェアの並行処理を簡単に活用でき、単純な使用においてはスレッドプールの利点の一部が提供されます。
タプルは、あらかじめ決められた次元を持つ異種オブジェクトから構成される集合です。タプルは、構造体のメンバ変数の一般化と考えることができます。
TR1タプル型のC++11バージョンは、可変引数テンプレートなどのC++11の機能を活用しています。TR1バージョンを適切に実装するには、実装定義の最大包含型数と、かなりのマクロ操作が必要でした。対照的に、C++11バージョンの実装では、明示的な実装定義の最大型数は必要ありません。コンパイラはテンプレートインスタンス化のための内部的な最大再帰深度を持ちますが(これは通常のことです)、C++11バージョンのタプルはこの値をユーザーに公開しません。
可変引数テンプレートを使用すると、タプルクラスの宣言は次のようになります。
namespace std { template < class ... Ts > class tuple ; }タプル型の定義と使用例:
using Types = std :: tuple < int , double , long & , const char *> ; long lengthy = 12 ; Types proof ( 18 , 6.5 , lengthy , "Ciao!" );lengthy = std :: get <0> ( proof ); // 'lengthy' に値 18 を代入します。std :: get <3> ( proof ) = " Beautiful !" ; // タプルの 4 番目の要素を変更します。タプルの内容を定義しなくてもタプルを作成することは可能ですproofが、そのためにはタプルの要素の型にデフォルトコンストラクタが存在する必要があります。さらに、タプルを別のタプルに代入することも可能です。2つのタプルの型が同じ場合、各要素の型にはコピーコンストラクタが必要です。そうでない場合は、右側のタプルの各要素の型が左側のタプルの対応する要素の型に変換可能であるか、左側のタプルの対応する要素の型に適切なコンストラクタが存在する必要があります。
using std :: string ; using T1 = std :: tuple < int , double , string > ; using T2 = std :: tuple < char , short , const char *> ;T1 t1 ; T2 t2 ( 'X' , 2 , "Hola!" ); t1 = t2 ; // OK、最初の 2 つの要素は変換できます。// 3 番目の要素は 'const char *' から構築できます。と同様にstd::make_pair、型推論を使用して を自動的に作成する がstd::pair存在し、そのようなタプルを宣言するのに役立ちます。は、タプルの展開に役立つ左辺値参照のタプルを作成します。もここで役立ちます。例を参照してください。std::make_tuplestd::tupleautostd::tiestd::ignore
#include <string> #include <tuple>std :: stringを使用します。auto record = std :: make_tuple ( "Hari Ram" , "New Delhi" , 3.5 , 'A' ); string name ; float gpa ; char grade ; std :: tie ( name , std :: ignore , gpa , grade ) = record ; // std::ignore は場所名を削除するのに役立ちますstd :: cout << name << ' ' << gpa << ' ' << grade << std :: endl ;関係演算子(要素数が同じタプル間)が使用可能であり、タプルの特性をチェックするための2つの式が使用可能です(コンパイル時のみ)。
std::tuple_size<T>::valueタプル内の要素数を返しますT。std::tuple_element<I, T>::typeIタプルのオブジェクト番号の型を返しますT。C++標準ライブラリにハッシュテーブル(順序付けされていない連想コンテナ)を含めることは、最も頻繁に寄せられる要望の一つです。C++03では時間的な制約のみで採用されませんでした。ハッシュテーブルは最悪の場合(衝突が多数発生する場合)には平衡木よりも効率が劣りますが、多くの実際のアプリケーションではより優れたパフォーマンスを発揮します。
衝突は線形連鎖によってのみ処理されます。これは、委員会が、多くの本質的な問題(特に要素の消去が許容される場合)を引き起こすオープンアドレッシングのソリューションを標準化することが適切ではないと考えたためです。独自のハッシュテーブル実装を開発した非標準ライブラリとの名前の衝突を避けるため、「hash」の代わりに「unordered」という接頭辞が使用されました。
新しいライブラリには4種類のハッシュテーブルがあり、同じキー(一意のキーまたは同等のキー)を持つ要素を受け入れるかどうか、および各キーを関連付けられた値にマッピングするかどうかによって区別されます。これらは、既存の4つの二分探索木ベースの連想コンテナに対応し、unordered_という接頭辞が付いています。
新しいクラスはコンテナクラスのすべての要件を満たし、要素にアクセスするために必要なすべてのメソッドを備えています: insert、erase、begin、end。
この新機能は、C++言語のコア拡張機能を一切必要とせず(ただし、実装ではC++11の様々な言語機能を活用します)、ヘッダーの小さな拡張と、ヘッダーと<functional>を導入するだけで済みました。既存の標準クラスに対するその他の変更は一切必要なく、標準ライブラリの他の拡張機能にも依存していません。<unordered_set><unordered_map>
ハッシュテーブルに加えて、標準ライブラリにさらに2つのコンテナが追加されました。1つ目は、std::array固定サイズのコンテナで、std::vectorCスタイルの配列よりも効率的でありながら、より安全で使いやすいものです。2つ目は、単方向連結リストで、双方向の反復処理が不要な場合に、std::forward_list二重連結リストよりもスペース効率の良いストレージを提供します。std::list
新しいヘッダーファイルで定義されている新しいライブラリは、<regex>いくつかの新しいクラスで構成されています。
std::regex。std::match_results。std::regex_iteratorは、正規表現のすべてのマッチを反復処理するために使用されます( にはstd::cregex_iterator、const char*にはstd::sregex_iteratorを使用std::string)。この関数std::regex_searchは検索に使用され、「検索と置換」にはstd::regex_replace新しい文字列を返す関数が使用されます。[ 26 ]
以下は使用例ですstd::regex_iterator。
#include <regex>using std :: regex ; using std :: sregex_iterator ; using std :: string ;string pattern = R " ( [^ ,.\t\n]+ ) " ; // スペース、カンマ、ピリオド、タブ、改行で区切られた単語を検索string target = "Unseen University - Ankh-Morpork" ;regex re ( pattern ); // 無効なパターンでは例外が発生します// 正規表現イテレータを使用して、「target」のすべての単語を「pattern」の文字で区切って識別します。for ( sregex_iterator it ( target . begin (), target . end (), re ); it != re . end (); ++ it ) { string s = it -> str (); std :: cout << s << std :: endl ; }このライブラリは<regex>、既存のヘッダーファイルを変更する必要も(必要に応じて使用しますが)、コア言語を拡張する必要もありません。POSIX Cでは、正規表現は<regex.h>を介して利用できます。
C++11 では、 TR1 に対する改良と改善が提供されています。はstd::unique_ptr非推奨です。std::shared_ptrstd::weak_ptrstd::auto_ptr
C標準ライブラリは、関数を使用して擬似乱数randを生成する機能を提供しています。ただし、アルゴリズムは完全にライブラリベンダーに委ねられています。C++はこの機能をそのまま継承しましたが、C++11では擬似乱数を生成するための新しい方法が追加されました。
C++11の乱数生成機能は、2つの部分に分かれています。1つは乱数生成器の状態を保持し、擬似乱数を生成する生成エンジン、もう1つは結果の範囲と数学的な分布を決定する分布です。これら2つが組み合わさって乱数生成器オブジェクトを形成します。
C標準とは異なりrand、C++11のメカニズムには3つの基本ジェネレーターエンジンアルゴリズムが付属します。
C++11では、いくつかの標準ディストリビューションも提供されています。
uniform_int_distribution、uniform_real_distribution、bernoulli_distribution、binomial_distribution、geometric_distribution、negative_binomial_distribution、poisson_distribution、exponential_distribution、gamma_distribution、weibull_distribution、extreme_value_distribution、normal_distribution、lognormal_distribution、chi_squared_distribution、cauchy_distribution、fisher_f_distribution、student_t_distribution、discrete_distribution、piecewise_constant_distributionそしてpiecewise_linear_distribution。ジェネレーターと分布は、この例のように組み合わされます。
#include <functional> #include <random>using std :: mt19937 ; using std :: uniform_int_distribution ;uniform_int_distribution < int > distribution ( 0 , 99 ); mt19937 engine ; // Mersenne twister MT19937 auto generator = std :: bind ( distribution , engine ); int random = generator (); // 0 から 99 の間の一様整数変数を生成します。int random2 = distribution ( engine ); // distribution オブジェクトと engine オブジェクトを直接使用して別のサンプルを生成します。ラッパー参照は、クラステンプレートのインスタンスから取得されます。ラッパー参照は、reference_wrapper C++ 言語の通常の参照 (' ') に似ています&。任意のオブジェクトからラッパー参照を取得するには、関数テンプレートrefを使用します (定数参照の場合はcrefを使用します)。
ラッパー参照は、特に関数テンプレートにおいて有用です。関数テンプレートでは、パラメータのコピーではなく、パラメータへの参照が必要となるためです。
#include <functional> #include <iostream>// この関数は、パラメータ 'r' への参照を受け取り、それをインクリメントします。void func ( int & r ) { r ++ ; }// テンプレート関数。template < class F , class P > void g ( F f , P t ) { f ( t ); }int main () { int i = 0 ; g ( func , i ); // 'g<void(int& r), int>' がインスタンス化されると// 'i' は変更されません。std :: cout << i << std :: endl ; // 出力 -> 0g ( func , std :: ref ( i )); // 'g<void(int& r), reference_wrapper<int>>' がインスタンス化されると // 'i' が変更されます。std :: cout << i << std :: endl ; // 出力 -> 1 }この新しいユーティリティは既存の<functional>ヘッダーファイルに追加されたものであり、C++言語のさらなる拡張は必要としなかった。
関数オブジェクトのポリモーフィックラッパーは、意味論と構文において関数ポインタに似ていますが、より緩やかな束縛を持ち、ラッパーの引数と互換性のある引数を持つ呼び出し可能なもの(関数ポインタ、メンバ関数ポインタ、ファンクタなど)を無差別に参照できます。
例を挙げると、その特徴がより明確になるだろう。
#include <functional>using std :: function ; using std :: plus ;// テンプレートクラス「function」を使用したラッパーの作成。function < int ( int , int ) > func ;plus < int > add ; // 'plus' は 'template <class T> T plus(T, T) ;' として宣言されます。// すると 'add' は 'int add( int x, int y )' の型になります。func = add ; // OK - パラメータと戻り値の型は同じです。int a = func ( 1 , 2 ); // 注: ラッパー 'func' がどの関数も参照しない場合、// 例外 'std::bad_function_call' がスローされます。function < bool ( short , short ) > func2 ; if ( ! func2 ) { // 'func2' にはまだ関数が割り当てられていないため、True になります。bool adjacent ( long x , long y ); func2 = & adjacent ; // OK - パラメータと戻り値の型は変換可能です。struct Test { bool operator ()( short x , short y ); };テストcar ; // 'std::ref' は、構造体 'car' のメンバ関数 'operator()' のラッパーを返すテンプレート関数です。 func = std :: ref ( car ); } func = func2 ; // OK - パラメータと戻り値の型は変換可能です。テンプレートクラスはfunctionヘッダーファイル内で定義されており<functional>、C++言語に変更を加える必要はありませんでした。
メタプログラミングとは、別のプログラム(あるいは自身)を作成または変更するプログラムを作成することです。これはコンパイル時または実行時に発生します。C ++標準委員会は、テンプレートを介してコンパイル時にメタプログラミングを行うためのライブラリを導入することを決定しました。
以下は、C++03規格を使用したメタプログラムの例です。整数指数を計算するためのテンプレートインスタンスの再帰処理です。
template < int B , int N > struct Power { // 再帰呼び出しと再結合。enum { VALUE = B * Power < B , N - 1 >:: VALUE }; };template < int B > struct Power < B , 0 > { // ''N == 0'' 終了条件。enum { VALUE = 1 }; };int quartic_of_three = Power < 3 , 4 >:: VALUE ;多くのアルゴリズムは様々な種類のデータに対して動作できます。C++のテンプレートは汎用プログラミングをサポートし、コードをより簡潔で使いやすいものにします。しかしながら、アルゴリズムが使用するデータ型に関する情報を必要とすることはよくあります。この情報は、型特性を使用してテンプレートクラスのインスタンス化時に抽出できます。
型特性は、オブジェクトのカテゴリとクラス(または構造体)のすべての特性を識別できます。これらは新しいヘッダーで定義されています<type_traits>。
次の例では、テンプレート関数「elaborate」があり、これは指定されたデータ型に応じて、提案された 2 つのアルゴリズム ( Algorithm::perform) のいずれかをインスタンス化します。
#include <type_traits>using std :: is_floating_point ; using std :: is_integral ;// 最初の操作方法。template < bool B > struct Algorithm { template < class T1 , class T2 > static int perform ( T1 & , T2 & ) { // ... } };// 2つ目の操作方法。template <> struct Algorithm < true > { template < class T1 , class T2 > static int perform ( T1 , T2 ) { // ... } };// 'elaborate' をインスタンス化すると、適切な操作方法が自動的にインスタンス化されます。template < class T1 , class T2 > int elaborate ( T1 A , T2 B ) { // 'T1' が整数で 'T2' が浮動小数点数の場合のみ、2 番目の方法を使用します。 // それ以外の場合は、最初の方法を使用します。return Algorithm < is_integral < T1 >:: value && is_floating_point < T2 >:: value >:: perform ( A , B ) ; }ヘッダーで定義されている型特性を介して<type_traits>、型変換操作を作成することもできます(テンプレート内ではstatic_cast、およびだけでは不十分です)。const_cast
この種のプログラミング手法は、洗練された簡潔なコードを生成しますが、弱点はデバッグです。コンパイル中は煩雑で、プログラム実行中は非常に困難です。
テンプレート関数オブジェクトの戻り値の型をコンパイル時に決定するのは直感的ではありません。特に、戻り値が関数のパラメータに依存する場合はなおさらです。例として、次の例を挙げます。
struct Clear { // パラメータの型は戻り値の型と同じです。int operator ()( int ) const ; double operator ()( double ) const ; };template < class Obj > class Calculus { private : Obj member ; public : template < class Arg > Arg operator ()( Arg & a ) const { return member ( a ); } };クラステンプレートをインスタンス化すると、の関数オブジェクトは常にの関数オブジェクトと同じ戻り値の型になります。ただし、以下のクラスの場合:Calculus<Clear>calculusClearConfused
struct Confused { // パラメータの型が戻り値の型と一致しません。double operator ()( int ) const ; int operator ()( double ) const ; };をインスタンス化しようとすると、の戻り値の型がクラスの戻り値の型と異なってしまいます。コンパイラは、からへの変換、およびその逆の変換について警告を生成する可能性があります。Calculus<Confused>CalculusConfusedintdouble
std::result_ofTR1では、関数オブジェクトの戻り値の型を宣言ごとに決定して使用できるテンプレートクラスが導入され、C++11で採用されました。このテンプレートクラスは、関数オブジェクトの戻り値の型を導出するためにオブジェクトCalculusVer2を使用します。std::result_of
#include <type_traits>std :: result_of を使用します。template < class Obj > class CalculusVer2 { private : Obj member ; public : template < class Arg > typename result_of < Obj ( Arg ) >:: type operator ()( Arg & a ) const { return member ( a ); } };このように、関数オブジェクトのインスタンスでは、変換、警告、またはエラーは発生しません。CalculusVer2<Confused>
TR1 版からの唯一の変更点std::result_ofは、TR1 版では実装が関数呼び出しの結果型を判定できない場合でも許容されていたことです。C++ が をサポートするように変更されたためdecltype、C++11 版ではstd::result_ofこれらの特殊なケースは不要となり、実装はすべての場合において 型を計算する必要があります。
別のTRへ向かう:
延期した:
シーケンスポイントという用語は削除され、ある操作が別の操作より先に実行されるか、または2つの操作が順序付けられていないかを指定することに置き換えられた。[ 30 ]
キーワードの使用は、エクスポートされたテンプレートexportとともに削除されました。[ 31 ]キーワードは予約語として残され、後にモジュールの追加とともにC++20で再導入されました。export
動的な例外指定は非推奨です。[ 31 ]例外をスローしない関数のコンパイル時指定はnoexceptキーワードで可能で、最適化に役立ちます。
std::auto_ptrは非推奨となり、に置き換えられましたstd::unique_ptr。
関数オブジェクト基底クラス(std::unary_function、std::binary_function)、関数へのポインタへのアダプタ、メンバへのポインタへのアダプタ、およびバインダークラスはすべて非推奨です。
register付属書D.2には、「キーワードをストレージクラス指定子(§7.1.1)として使用することは非推奨です」と記載されています。
最終標準/レポートを除き、すべてのC++委員会文書は、すべての作業草案を含め、自由に公開されており、その多くは公開された標準に非常に近いものです。2012年1月の作業草案には、C++11標準に加えて、軽微な編集上の変更が含まれています。