訳者注
下記の文章は C++11 - the new ISO C++ standard の暫定勝手和訳です。 翻訳は現在進行中であり、未完成かつ不正確である可能性があります。 っていうか未完成かつ不正確です。 正しい情報を必要とされる方は、原文を当たってくださいますようよろしくお願いします。 誤訳の指摘は大歓迎です。

Morgan Stanley | コロンビア 大学 | チャーチル・カレッジ, ケンブリッジ

ホーム | C++ | FAQ | 技術的な FAQ | 出版物 | WG21 文書 | プログラミング言語 C++ | Tour++ | プログラミング | C++ の設計と進化 | 略歴 | インタビュー | 動画 | 引用 | アプリケーション | ガイドライン | コンパイラ

C++11 - 新 ISO C++ 標準

2016年08月19日更新 (訳注: 和訳は2021年09月19日更新)

この文書 (訳注: 原文) は Bjarne Stroustrup が記述、更新している。 建設的なコメント、訂正、参考資料、提案はもちろん大いに歓迎する。 現在、著者は参考資料の充実化と清書に取り組んでいる。

翻訳:

著者は、自身が理事を務める C++ 財団が保守する、新たな、統合された、isocpp.org C++ FAQ に寄贈した。 この FAQ の保守はどんどん頻繁にされるようになるだろう。

C++11 は 2011 年に承認された ISO C++ 標準である。 以前の標準は、しばしば C++98 や C++03 と呼ばれる; C++98 と C++03 の違いはごく僅かで技術的なものなので、ユーザの興味はひかないだろう。

最近のワーキングペーパー が閲覧可能だ。 これは 2011 年 8 月の国際投票において 21-0 で正式に承認された国際標準最終案とほとんど同じだ。 正式に標準が承認されるまで、著者達は来たるべき標準を C++0x と呼んでいた。 名前の整合性をとるように更新する時間が著者にはなかったのだが、まあなんだ、C++0x という名前が気に入っているわけだ。 :-) "C++0x"という名前は、著者やその他の人々が、C++08 または C++09 になると思っていた時の名残である。 「x」は十六進数だと考えて欲しい (つまり C++0B == C++11)。

C++11/C++0x に関連する公式の文書は ISO C++ 委員会のウェブサイトにある。 委員会の公式な名称は SC22 WG21 だ。

注意: この FAQ は長きに亘って更新中であり続けるだろう。 意見、質問、参考資料、訂正、提案を歓迎する。


目的

C++11 FAQ の目的は、 この FAQ の目的は、個々の機能についての包括的な議論を提供することではないし、その使用方法を詳細に説明することでもないことを了解いただきたい。 目標は C++11 が提供することになっているものを紹介する簡単な例を提示することだ (+ 参考資料)。 著者の理想は、機能の複雑さに依らず「一機能につき最大一ページ」だ。 詳細については大抵、参考資料中にあるだろう。


質問の一覧

以下はいくらか高水準な質問である

質問 個々の言語機能についての質問は以下の通り:

著者はしばしば提案書から例を引いている。 これは提案書の作者のおかげである。 多くの例は、著者自身の著述が元になっている。

質問 個々の標準ライブラリ機能についての質問は以下の通り:

以降は上述した個々の質問に対する答えである。


C++11 のことを著者はどう思っているのか?

これは (著者にとって) 驚くほどよくある質問だ。 ことによると一番多い質問かもしれない。 びっくりするかも知れないが、C++11 はほとんど新しい言語のように感じる: 各々のパーツは以前よりもうまくフィットするようになったし、著者は高水準スタイルのプログラミングが以前よりもより自然になり、かつ効率は以前のままであることを確認した。 C++ を、より良い C やオブジェクト指向言語として恐る恐る使おうとすると、ポイントを外すことになるだろう。 単純に、抽象化がこれまでよりも更にフレキシブルかつ手軽になったのだ。 古いマントラを当てにしてもらいたい: もしそれが別々のアイディアあるいはオブジェクトだと思うのであれば、それをプログラムに直接表現すればよい; 実世界のオブジェクトをモデル化し、コードに直接抽象化するのだ。 これからはもっと簡単になる: あなたのアイディアは、一つしかない「万能サイズ」の抽象化機構ではなく、 列挙体、 オブジェクト、 class (例えば default 指定)、 クラス階層 (例えば 継承コンストラクタ)、 template、 別名、 例外、 ループスレッド、 等に結びつけられるだろう。

著者の理想は、システム設計と実装について異なる考えを持つプログラマを支援するためのプログラミング言語機能として使われることだ。 著者は、C++11 にそれが可能だと考えている - そして、C++ プログラマのみならず、システムプログラミングの一般的かつ非常に幅広い分野で様々な現代的プログラミング言語に慣れているプログラマに対しても、可能だと考えている。

言い換えれば、著者はまだ楽観主義者である。


C++11 が公式の標準になるのはいつか?

もうなっている! 公式コメントのための最初の草案は 2008 年 9 月に発表された。 最終草案 (FCD) は、2011 年 3 月 25 日の ISO C++ 委員会において満場一致で承認され、2011 年 8 月に国際投票で 21-0 で正式に承認された。 この標準は年内 (2011) に発行済だ。

新しい標準がどのような姿になるかはもう分かっている (提供される個々の機能の小さい変更を除く)。 この新しい標準は C++11 と呼ばれるようになるだろうが、ちょっとしたお役所仕事の遅れのせいで C++12 になるかも知れない。 個人的には、何もつけずに C++ と呼び、以前の C++ と区別して年号をつける必要がある時に限り、ARM C++、C++98、C++03 と呼ぶのが好みである。 移行期間の間、著者はあちこちで C++0x という用語を使うだろう。 「x」は十六進数だと考えていただきたい。


コンパイラが C++11 を実装するのはいつか?

現在出荷されているコンパイラ (GCC G++、Clang C++、IBM C++、Microsoft C++ 等) は既に多くの C++11 機能を実装している。 例えば、新しい標準ライブラリの全て、あるいは殆どを同梱することが明らかで一般的なようだ。

著者は、2012 年内のどこかで最初の完全な C++11 コンパイラが現れるのではないかと思うが、いつそういったコンパイラが出荷されるかとか、いつ全てのコンパイラが C++11 の機能を全部提供するのがいつになるかとかは気にしていない。 全ての C++11 機能はどこかで誰かが実装してきたものなので、実装者はその経験を参考にすることができるということは明記しておく。

以下に提供元からの C++11 情報へのリンクを挙げる:


新しい標準ライブラリが使えるようになるのはいつか?

新しい標準ライブラリの初期バージョンは、現在、GCC や Clang、Microsoft の実装に同梱されているし、 boost から利用することもできる。


C++11 が提供する新しい言語機能は何か?

誰かが良いアイディアだと考える機能を単純に追加していくだけではプログラミング言語は進歩しない。 実際、基本的にほとんどの現代的なプログラミング言語の機能は C++ で誰かしらから著者へ提案されている: C99、C#、Java、Haskell、Lisp、Python、Ada のスーパーセット言語がどんな風になるか、想像してみるといい。 問題をより複雑にするのは、それで過去の機能を(委員会がその機能は良くないという合意をしたとしても)切り捨てられるわけではないということだ: 経験が示すところによれば、ユーザは全ての実装者に時代遅れになったり廃止されたりした機能を互換性オプションの下で (あるいはデフォルトで) 何十年も提供し続けるよう要求するのだ。

提案の洪水の中から合理的に選択するために、著者達は明確な設計目標のあり方を工夫した。 著者達は完全にそれに従ったが、全ての細部にわたって委員会を導くほどには完全ではなかった (そして、著者の意見を言わせていただくと、完全たり得ない)。

その結果、プログラミング言語の抽象性が大きく進歩した。 C++ がエレガントでフレキシブルに、かつ手書きで調製したコードに比べてゼロコストで表現できる範囲が大幅に広がったのだ。 著者達が「抽象化」と言うと、一般的には「クラス」や「オブジェクト」だと考えられてしまう。 C++11 は遙かに先を行っている: 初期化リスト統一された初期化template の別名右辺値リファレンスdefault 及び delete 関数可変個引数 template のような機能の追加によって、明確かつ安全に記述できるユーザ定義型の範囲が広がった。 その実装は auto継承コンストラクタdecltype のような機能の追加で簡単になっている。 これらの改良は C++11 が新しい言語のように感じさせるのに十分だ。

受け入れられた言語機能の一覧については、機能の一覧を参照されたい。


C++11 が提供する新しい標準ライブラリは何か?

著者はもっと標準ライブラリを望んでいた。 しかしながら、標準ライブラリの定義は既に標準の規格文書のうち約70%になっている (それも、参照として含まれている C の標準ライブラリをカウントせずにだ)。 たとえ著者達のうちの誰かがもっと標準ライブラリを望んだとしても、ライブラリワーキンググループを鈍いと責めることは誰にもできないだろう。 初期化リスト右辺値リファレンス可変個引数 templatenoexceptconstexpr のような新しい言語機能を使うことで C++98 のライブラリが大きく進歩したことも特筆する価値がある。 C++11 の標準ライブラリは C++98 のものより使いやすくなり、性能も向上している。

受け入れられたライブラリの一覧については、ライブラリコンポーネントの一覧を参照されたい。


C++11 の作業の目標は何だったのか?

C++ はシステムプログラミング向きの汎用プログラミング言語であり 全体として C++11 の目標は以下の強化だった: 当然、これは非常に厳しい互換性の制約の下でなされる。 非常に希なことだが、新しいキーワード (例えば、static_assertnullptrconstexpr) を導入することで、委員会が標準準拠のコードを破壊しようとすることもある。

より詳しくは、以下を参照されたい:


委員会を導いた明確な設計目標は何か?

当然ながら、標準化には異なる人々と異なる組織が関わっており、異なった目標を持っている。 殊に、細かい点や優先度の点では大きく異なる。 更に、細かい目標は時と共に変わる。 委員会は万人が良いことだと認めることすらできないことがあるということを忘れないで貰いたい -- 委員会はボランティアで構成されており、リソースが極めて限られているのだ。 しかしながら、言語機能やライブラリについての実際の議論で、C++11 に相応しいか評価するのに使われた基準を以下に挙げる: 統合機能 (新旧の) が協調して動作することが鍵になることに -- そしてそれがほとんど全てなのだが -- 注意して欲しい。 全体は、単純な部分の総和よりも遙かに大きいのだ。

利用分野や利用方法に着目することでも、細かい目標を見て行くことができる:


委員会の文書はどこにあるのか?

委員会のウェブサイトの文書のセクションを参照すること。 多分細かい内容に圧倒されるだろう。 「課題の一覧」や「状況」 (例えば発展状況 (2008年7月)) の一覧を見ると良い。 キーとなるグループは以下の通り。 ここには最新の C++11 標準案がある。


C++11 に関する学術、技術文書はどこにあるのか?

この一覧は不完全だし、新しい文書が書かれるに従ってしばしば時代遅れになるだろう。 ここに掲載されるべき文書をご存知なら、著者に知らせて戴きたい。 また、文書の全てが最近の標準化の進展に完全に追従しているとは限らない。 著者はコメントを最新にするよう努めている。


他の C++11 に関する文書はどこにあるのか?

C++11 に関する情報量は、標準化が完成に近づき、C++ の実装が新しい言語機能とライブラリを提供し始めたのに伴って、増えつつある。 以下に挙げるのは情報源の短い一覧だ:


C++11 に関する動画はあるのか?

(著者を知る人達へ。 これは紛れもなく単なる FAQ の回答であって、著者の好きな質問への回答ではない; 著者は技術的な動画のファンではない - 動画は気が散るし、口述形式には小さな技術的誤りが多過ぎる)。

ある:


C++11 を学ぶのは難しいか?

え〜と、大量のコードを破壊することなく C++ から重要な機能を除去することはできないので、C++11 は C++98 よりも大きくなっている。 従って、全ての規約を学ぶつもりなら C++11 はより難しくなるだろう。 (学習者の視点から) 単純化のための道具を二つだけ挙げておく: 明らかに「ボトムアップ」の教育/学習方式では上述の利点を活かせないのだが、別のアプローチによるものは現在のところ (明らかに) ごく僅かしかない。 これは時間が経てば変わるだろう。


委員会はどのように運営されているのか?

ISO 標準化委員会、SC22 WG21 は、そういった委員会向けの ISO のルールの下で運営されている。 本当に妙な話なのだが、このルールは標準化されておらず、時と共に変わる。

多くの国に活発な C++ グループを抱える国内標準化団体がある。 これらのグループは会合を開いたりウェブで調整したりして、ISO の会合に代表を送ってくる。 カナダ、フランス、ドイツ、スイス、イギリス、アメリカは殆どの会合に出席する。 デンマーク、オランダ、日本、ノルウェー、スペイン、その他の国々は個人で出席するが、前者ほど頻繁ではない。

作業の殆どは会合と会合の間にウェブ越しに進行し、その結果が大量の委員会文書として WG21 のウェブサイトに掲載されている。

委員会の会合は年に二〜三回、一週間の間、開催される。 殆どの作業は、「コア」「ライブラリ」「発展」「並列性」等の分科会に分かれて行われる。 必要な場合は、「concept」や「メモリモデル」といった特定の緊急事案について、会合と会合の間に臨時ワーキンググループの会合が開催されることもある。 投票は主会合で行われる。 まず、その課題が委員会全体へ提示する準備ができているか、ワーキンググループで非公式な投票が実施される。 続いて、委員会の全体投票 (一人一票) が行われ、承認されれば国際投票となる。 著者達は多数の出席者と国々が合意しない状況に陥らないように大変気を使っている -- そうなれば長期間の論争になるのが分かり切っているからだ。 公式案の最終投票は国別の標準化団体毎に郵送で行われる。

委員会は C の標準化グループ (SC22 WG14) や POSIX と公式に連携しており、その他のグループとも何らかの公式な連絡を取り合っている。


委員会に加わっているのは誰か?

委員会は多数の人員 (約 250 名) で構成されており、年に二〜三回ある一週間会合では、その内 90 人以上が出席する。 それに加えて、複数の国々に国内標準化団体があり、その会合が開かれる。 殆どのメンバーは会合に出席するか、電子メールで議論するか、委員会の熟慮に資する文書を投稿するといった形で関与する。 また、殆どのメンバーには支援してくれる友人や仲間がいる。 初日から、委員会には多くのメンバーと国々が参加しており、全出席者は半ダース〜一ダースの国々からやってくる。 最終投票は約 20 ヶ国の標準化団体によって行われる。 従って、ISO C++ の標準化は相当に重い作業であり、我田引水的に完璧なプログラミング言語を作るために似たような人達の小集団がやっているようなものではないのだ。 標準規格とは、それと共にある全ての人達に最大の便宜を供することができる、とボランティアの集団が合意に達することができるものなのだ。

当然、多くの (全てではないが) ボランティア達が C++ に関わる日常の仕事に就いている: 著者達の中にはコンパイラ屋、ツール屋、ライブラリ屋、アプリケーション屋 (少なすぎる)、研究者 (少しは)、コンサルタント、テストスイート屋、等々がいる。

以下に挙げるのは参加している組織のごく一部だ: Adobe、 Apple、 Boost、 Bloomberg、 EDG、 Google、 HP、 IBM、 Intel、 Microsoft、 Red Hat、 Sun。

以下に挙げるのは文献やウェブで名前を見るかも知れない人達の短い一覧だ: Dave AbrahamsMatt AusternPete BeckerHans BoehmSteve ClamageLawrence CrowlBeman DawesFrancis GlassborowDoug GregorPablo HalpernHoward HinnantJaakko JarviJohn Lakos、 Alisdair Meredith、 Jens Maurer、 Jason Merrill、 Sean ParentP.J. PlaugerTom PlumGabriel Dos ReisBjarne StroustrupHerb SutterDavid VandevoordeMichael Wong。 ここに挙げることができなかった、200 人以上いる現在及び過去のメンバーの方々にはご容赦願いたい。 また、様々な文書の執筆者一覧にも目を向けて戴きたい: 標準は、匿名の委員ではなく、(多くの) 個人によって書かれているのだ。

あるいは、WG21 の文書の執筆者リストを調べて専門的技術の息吹と深みに感動するかもしれないが、たくさん書いたわけではないにせよ、標準化作業に貢献した人も大勢いることを忘れないで欲しい。


C++1y はあるのか?

ほぼ間違いなくある -- 委員会が C++0x の〆切をやぶったせいではない。 小規模な改定となる C++14 の計画はうまく進捗しており (ワーキングドラフトの投票や実装がなされている)、大規模な改定は 2017 年に C++17 として計画されている。


「concept」に何が起きたのか?

「concept」は template 引数が必要とする適切な仕樣を指定することができるように設計された機能だった。 残念ながら、委員会は concept の更なる作業で標準化が深刻に遅延すると判断し、作業中の文書からこの機能を削除した。 経緯については、著者による C++0x 「コンセプト削除」の決定DevX インタビュー コンセプトと C++0x への影響 を参照のこと。

徹底的に単純化された『concept lite』が (テクニカルレポートとして) C++14 の一部になるだろう。

この文書の「concept」の項は削除せずに残してある:


気に入らない機能はあるか?

ある。 C++98 にも気に入らない機能はあった (例えばマクロ)。 これは、著者が何かを好んだり、著者がやりたい何かのために便利だと考えたりするのとは別の議論だ。 論点は、ある考えをサポートすることに十分説得力があると感じられるか、場合によっては、ユーザコミュニティにそういう用法がしっかり根づいているためサポートする必要があるか、ということなのだ。


__cplusplus

C++11 では、マクロ __cplusplus の値が現在の 199711L と異なる (より大きい) 値となる。


auto -- 初期化子からの型導出

以下を考えよ。

	auto x = 7;
ここで x は、初期化子の型の通り int 型となる。 一般に、

	auto x = 式;
と書くことができ、x の型は「式」の計算結果の型になる。

変数の型を初期化子から導出する auto 型は、明らかに、型を正確に知るのや書くのが難しい場合に一番便利だろう。 以下を考えよ:


	template<class T> void printall(const vector<T>& v)
	{
		for (auto p = v.begin(); p!=v.end(); ++p)
			cout << *p << "\n";
	}
C++98 では、

	template<class T> void printall(const vector<T>& v)
	{
		for (typename vector<T>::const_iterator p = v.begin(); p!=v.end(); ++p)
			cout << *p << "\n";
	}
と書く必要があった。

変数の型が template 引数に強く依存している場合は、auto なしにコードを書くのは本当に難しくなるだろう。 例えば:


	template<class T, class U> void multiply(const vector<T>& vt, const vector<U>& vu)
	{
		// ...
		auto tmp = vt[i]*vu[i];
		// ...
	}
tmp の型は TU の乗算結果になるが、それが正確に何型であるか人間の読み手が見出すのは難しい。 しかし、もちろんコンパイラは、自身が扱っている適切な TU が何型であるかを知っている。

auto 機能はもっとも早く提案され実装された部分だ: 著者は 1984 年の早い時期に自分の Cfront で動作させていたが、C との互換性問題のせいで外したのだ。 この互換性問題は、C++98 と C99 が「暗黙の int」の削除を受け入れた時に解決した; 両方の言語で、全ての変数と関数が、明示的に型定義が必要になったのだ。 auto の古い意味 (「これはローカル変数だよ」) はもはや非合法となった。 複数の委員会メンバーが何百万行ものコードを洗ったが、数えるほどの使用例しか見つからなかった -- しかもほとんどはテストスイートか、あるいはバグのようだった。

auto は主にコードの表記を簡潔にするための機能なので、標準ライブラリの仕様には影響しない。

以下も参照。


範囲 for 文

begin() と end() を持つ STL シーケンスのようなイテレータを通じて指せるものなら何でも、範囲 for 文で「範囲」全体を反復処理できる。 全ての標準コンテナは範囲として使えるし、同様に std::string、初期化リスト、配列、それに istream のように begin() と end() が定義されているものなら何でも範囲になる。 例えば:

void f(vector<double>& v)
{
	for (auto x : v) cout << x << '\n';
	for (auto& x : v) ++x;	// 値を更新できるようにリファレンスを使う
}
これを「v 中の全ての x について (原文: for all x in v)」、v.begin() から始めて v.end() まで反復する、と読むこともできる。 もう一つの例:

	for (const auto x : { 1,2,3,5,8,13,21,34 }) cout << x << '\n';
begin() (と end()) は x.begin() として呼び出されるメンバ関数でも良いし、begin(x) として呼び出される独立した関数でも良い。 メンバ関数版の方が優先順位が高い。

以下も参照。


不等号閉じ括弧

以下を考えよ。

	list<vector<string>> lvs;
C++98 では、二つの > の間にスペースがないので、文法エラーになる。 C++11 では、この二つ > を正しく二つの template 引数リストの終わりだと認識する。

なぜこれが今まで問題だったのか? コンパイラフロントエンドはパース/ステージに構成されている。 もっとも簡単なモデルは以下のようになる:

これらのステージは理論的に (そして時には実用上の理由で) 厳密に分かれており、そのため >> をトークン (通常は右シフトか入力の意味) だと判定する構文解析器は、その意味を知らないのだ; 特に、template やネストした template の引数リストの意味は全く知らない。 しかしながら、この三つのステージがどうにかして協力しないと、この例を「正しく」処理することはできない。 この問題を解決に導くのに鍵となったことは、全ての C++ コンパイラが既にこの問題を理解しており、きちんとしたエラーメッセージを出力できている、という実績だった。

以下も参照。


既定動作の制御 -- default と delete

「コピーを禁止」するという一般的なイディオムを直接表現できるようになった:

	class X {
		// ...
		X& operator=(const X&) = delete;	// コピーの禁止
		X(const X&) = delete;
	};
逆に、既定のコピーの振る舞いが望ましいなら、それを明示することもできる:

	class Y {
		// ...
		Y& operator=(const Y&) = default;	// デフォルトコピーの意味
		Y(const Y&) = default;
	};
既定の動作を明示するのは冗長だ。 とは言え、コピー動作についてのコメントとして効果はあるし、(さらに悪いことに) 既定の振る舞いを意味するコピー動作を明示的に定義するユーザが珍しくない。 既定の振る舞いのままにしておくようコンパイラに指示する方法が単純なら、エラーになりにくいし、より良いオブジェクトコードを生成することもあるだろう。

「default」機構は既定動作を持つ全ての関数で使用できる。 「delete」機構はどんな関数でも使用できる。 例えば、このような望ましくない変換を消去することができる:


	struct Z {
		// ...

		Z(long long);     // long long で初期化できる
		Z(long) = delete; // それより短い初期化は不可
	};

以下も参照。


既定動作の制御: 移動とコピー

既定のままで、class には 5 つの操作がある: これらのどれかを宣言するのなら、全てを熟考して明示的に定義するか既定の動作を用いるかする必要がある。 コピー、移動、デストラクタは、自由に混ぜたり組み合わせたりできる独立した操作ではなく、密接に関連しあった操作であると考えること - 望み通りに組み合わせて指定することはできるが、それが意味を持つとは限らない。

移動、コピー、デストラクタのどれも、ユーザにより明示的に指定される (宣言、定義、=default、=delete) と、移動がデフォルト生成されなくなる。 移動、コピー、デストラクタのどれも、ユーザにより明示的に指定される (宣言、定義、=default、=delete) と、未宣言のコピー操作がデフォルト生成されるが、これは廃止予定であるため、頼ってはならない。 例えば:


	class X1 {
		X1& operator=(const X1&) = delete;	// コピーの禁止
	};
これは暗黙に X1 の移動も禁止する。 コピー初期化は許されるが、廃止予定だ。

	class X2 {
		X2& operator=(const X2&) = delete;
	};
これは暗黙に X2 の移動も禁止する。 コピー初期化は許されるが、廃止予定だ。

	class X3 {
		X3& operator=(X3&&) = delete;	// 移動の禁止
	};
これは暗黙に X3 のコピーも禁止する。

	class X4 {
		~X4() = delete;	// デストラクトの禁止
	};
これは暗黙に X4 の移動も禁止する。 コピーは許されるが、廃止予定だ。

著者は、これら五つの関数のうち一つを宣言するなら、全部を明示的に宣言することを強く推奨する。 例えば:


	template<class T>
	class Handle {
		T* p;
	public:
		Handle(T* pp) : p{pp} {}
		~Handle() { delete p; }		// ユーザ定義のデストラクタ: 暗黙のコピーや移動なし 

		Handle(Handle&& h) :p{h.p} { h.p=nullptr; }			// 所有権を移転
		Handle& operator=(Handle&& h) { delete p; p=h.p; h.p=nullptr; return *this; }	// 所有権を移転

		Handle(const Handle&) = delete;		// コピーなし
		Handle& operator=(const Handle&) = delete;

		// ...
	};

以下も参照。


enum class -- スコープ付きの強く型付けされた enum

enum class (「新しい enum」あるいは「強い enum」) は、従来の C++ の列挙体の三つの問題に焦点をあてている:

enum class (「強い enum」) は強く型付けされスコープを持つ:


	enum Alert { green, yellow, orange, red }; // 従来の enum

	enum class Color { red, blue };   // スコープ付きの強く型付けされた enum
	                                  // 列挙体の名前はスコープ内に閉じこめられる
	                                  // 暗黙的に int に変換されない
	enum class TrafficLight { red, yellow, green };

	Alert a = 7;              // エラー (これまでの C++ と同じ)
	Color c = 7;              // エラー: int → Color の変換は不可

	int a2 = red;             // ok: Alert → int の変換
	int a3 = Alert::red;      // C++98 ではエラー; C++11 では ok
	int a4 = blue;            // エラー: blue はスコープ外
	int a5 = Color::blue;     // エラー: Color → int の変換

	Color a6 = Color::blue;   // ok
このように、従来の enum はそのまま動作するが、enum の名前で修飾することもできるようになった。

新しい enum は、従来の列挙体 (名前付の値) と class (スコープ付きのメンバと無変換性) の側面を組み合わせたものなので、「enum class」と呼ばれる。

下敷きとなる型を指定できるようになったことで、列挙体の相互運用性と大きさの保証が単純になった:


	enum class Color : char { red, blue };	// コンパクトな表現

	enum class TrafficLight { red, yellow, green };  // 既定では、下敷きとなる型は int

	enum E { E1 = 1, E2 = 2, Ebig = 0xFFFFFFF0U };   // E はどのくらい大きい?
	                                                 // (古い規約が何と言おうが
	                                                 // これは「実装定義」)

	enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };   // これからは型を指定できる
enum の前方宣言も可能になった:

	enum class Color_code : char;     // (前方) 宣言
	void foobar(Color_code* p);       // 前方宣言の利用
	// ...
	enum class Color_code : char { red, yellow, green, blue }; // 定義
下敷きとなる型は、符号ありまたは符号なしの整数型でなくてはならない; 既定の型は int だ。

標準ライブラリでは、enum classe は

として使われている。 これらのうちいくつかには、== のような演算子が定義されている。

以下も参照。


constexpr -- 一般化された保証付の定数式

constexpr の仕組みは、 以下を考えよ。

	enum Flags { good=0, fail=1, bad=2, eof=4 };

	constexpr int operator|(Flags f1, Flags f2) { return Flags(int(f1)|int(f2)); }

	void f(Flags x)
	{
		switch (x) {
		case bad:         /* ... */ break;
		case eof:         /* ... */ break;
		case bad|eof:     /* ... */ break;
		default:          /* ... */ break;
		}
	}
ここで、constexpr は、この関数が単純な形式でなければならず、従ってコンパイル時に定数式として評価できることを表す。

コンパイル時に式が評価できることに加えて、コンパイル時に評価する必要があることを表したい場合、変数定義の前に constexpr (暗黙に const となる) を置くことで以下のように書ける:


	constexpr int x1 = bad|eof;	// ok

	void f(Flags f3)
	{
		constexpr int x2 = bad|f3;	// エラー: コンパイル時に評価できない
		int x3 = bad|f3;		// ok
	}
典型的な場合、大域オブジェクトや namespace オブジェクト、場合によっては読込専用記憶域に格納したいオブジェクトに対して、コンパイル時評価を保証したいことが多いだろう。

これは、コンストラクタを constexpr にできるくらい単純なオブジェクトや、そのようなオブジェクトを含む式に対しても機能する:


	struct Point {
		int x,y;
		constexpr Point(int xx, int yy) : x(xx), y(yy) { }
	};

	constexpr Point origo(0,0);
	constexpr int z = origo.x;

	constexpr Point a[] = {Point(0,0), Point(1,1), Point(2,2) };
	constexpr int x = a[1].x;	// x は 1 になる
constexprconst を一般的に置き換えるものではない (し、その逆も然りである) ことに注意:

以下も参照。


decltype -- 式の型

decltype(E) は名前や式 E の型 (「宣言された型 (原文: declared type)」) であり、宣言文で使うことができる。 例えば:

	void f(const vector<int>& a, vector<float>& b)
	{
		typedef decltype(a[0]*b[0]) Tmp;
		for (int i=0; i<b.size(); ++i) {
			Tmp* p = new Tmp(a[i]*b[i]);
			// ...
		}
		// ...
	}
この考えは、総称型プログラミング業界では長い間「typeof」という名前で呼ばれることが多かったが、実際の typeof の実装は不完全で、しかも互換性がなかったため、標準の名前は「decltype」になった。

単に、変数を初期化するための型が欲しいだけなら、auto がよりシンプルな選択肢であることが多いだろう。 本当に decltype が必要になるのは、変数以外、例えば戻り値型のような型が欲しい場合だ。

以下も参照。


初期化リスト

以下を考えよ。
 
	vector<double> v = { 1, 2, 3.456, 99.99 };
	list<pair<string,string>> languages = {
		{"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
	}; 
	map<vector<string>,vector<int>> years = {
		{ {"Maurice","Vincent", "Wilkes"},{1913, 1945, 1951, 1967, 2000} },
		{ {"Martin", "Ritchards"}, {1982, 2003, 2007} }, 
		{ {"David", "John", "Wheeler"}, {1927, 1947, 1951, 2004} }
	}; 
初期化リストは、もはや配列だけのものではない。 {} リストを受取るための仕組みは、std::initializer_list<T> 型の引数を受取る関数 (しばしばコンストラクタ) による。 例えば:

	void f(initializer_list<int>);
	f({1,2});
	f({23,345,4567,56789});
	f({});	// 空のリスト
	f{1,2};	// エラー: 関数呼出 ( ) がない

	years.insert({{"Bjarne","Stroustrup"},{1950, 1975, 1985}});
初期化リストの長さは可変だが、型は一様でなくてはならない (全ての要素が template 引数型 T、もしくは T へ変換可能な型でなくてはならない)。

コンテナは初期化リストコンストラクタを以下のように実装してもよい:


	template<class E> class vector {
	public:
   		vector (std::initializer_list<E> s) // 初期化リストコンストラクタ
   		{
			reserve(s.size());	// 正確な領域長を取得
			uninitialized_copy(s.begin(), s.end(), elem);	// 要素の初期化 (elem[0:s.size()) の範囲)
			sz = s.size();	// vector の大きさを設定
   		}
   	
		// ... 上述の通り ...
	};

直接初期化とコピー初期化の差異は、{} 初期化でもそのままだが、{} 初期化である以上、あまり相関関係はなくなる。 例えば、std::vector は、int からの explicit コンストラクタと初期化リストコンストラクタを持っている:


	vector<double> v1(7);	// ok: v1 は 7 つの要素を持つ
	v1 = 9;			// エラー: int から vector<double> への変換は不可
	vector<double> v2 = 9;	// エラー: int から vector<double> への変換は不可

	void f(const vector<double>&);
	f(9);				// エラー: int から vector<double> への変換は不可

	vector<double> v1{7};		// ok: v1 は 1 つの要素を持つ (値は 7.0)
	v1 = {9};			// ok: v1 は 1 つの要素を持つようになった (値は 9.0)
	vector<double> v2 = {9};	// ok: v2 は 1 つの要素を持つ (値は 9.0)
	f({9});				// ok: f がリスト { 9 } で呼び出される

	vector<vector<double>> vs = {
		vector<double>(10), 	// ok: explicit コンストラクタ (10 要素)
		vector<double>{10},	// ok: explicit コンストラクタ (1 要素、値は 10.0)
		10 			// エラー: vector のコンストラクタは explicit
	};	

関数は、initializer_list に対して、不変なシーケンスとしてアクセスすることができる。 例えば:


	void f(initializer_list<int> args)
	{
		for (auto p=args.begin(); p!=args.end(); ++p) cout << *p << "\n";
	}

単独の std::initializer_list 型の引数を取るコンストラクタを初期化リストコンストラクタと呼ぶ。

標準ライブラリコンテナ、stringregex は初期化リストコンストラクタや代入演算子等を持っている。 初期化リストを、例えば範囲 for 文で、範囲として使うこともできる。

初期化リストは統一および一般化された初期化の枠組みの一環だ。

以下も参照。


縮小変換の禁止

問題点: C と C++ は暗黙のうちに切り捨ててしまう:

	int x = 7.3;		// おっと!
	void f(int);
	f(7.3);			// おっと!
しかしながら、C++11 の {} 初期化は縮小変換を行わない:

	int x0 {7.3};	// エラー: 縮小変換
	int x1 = {7.3};	// エラー: 縮小変換
	double d = 7;
	int x2{d};		// エラー: 縮小変換 (double から int)
	char x3{7};		// ok: 7 は int だが、これは縮小変換ではない
	vector<int> vi = { 1, 2.3, 4, 5.6 };	// エラー: double から int への縮小変換
C++11 での大量の非互換を避けるため、何が縮小変換にあたるかを決定する際に、初期化子の型ではなく実際の値 (上記の例では 7) で判断する。 もし、元の値が代入先の値として正確に表現できるのなら、それは縮小変換ではない。
	char c1{7};	// OK: 7 は int だが、char に収まる
	char c2{77777};	// エラー: 縮小変換 (8-bit char と仮定)
浮動小数から整数への変換は、常に縮小変換と看做されることに注意すること -- たとえ、7.0 から 7 であってもだ。

以下も参照。


委譲コンストラクタ

C++98 では、二つのコンストラクタに同じことをさせたい場合、自力で同じコードを書くか、「init() 関数」を呼び出す必要があった。 例えば:

	class X {
		int a;
		void validate(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
	public:
		X(int x) { validate(x); }
		X() { validate(42); }
		X(string s) { int x = lexical_cast<int>(s); validate(x); }
		// ...
	};

これは明らかに可読性の邪魔になるし、繰り返し書くのはエラーになりやすい。 どちらもメンテナンスには邪魔だ。 そこで、C++11 では、一つのコンストラクタを別のコンストラクタのために定義することができるようになった:


	class X {
		int a;
	public:
		X(int x) { if (0<x && x<=max) a=x; else throw bad_X(x); }
		X() :X{42} { }
		X(string s) :X{lexical_cast<int>(s)} { }
		// ...
	};

以下も参照


class 内メンバ初期化子

C++98 では、整数型の static const メンバしか class 内で初期化できなかった。 この制限は初期化がコンパイル時点で行えることを保証するためのものだ。 例えば:

	int var = 7;

	class X {
		static const int m1 = 7;        // ok
		const int m2 = 7;                	// エラー: static でない
		static int m3 = 7;              // エラー: const でない
		static const int m4 = var;       	// エラー: 定数式でない初期化
		static const string m5 = "odd"; // エラー: 整数型でない
		// ...
	};
C++11 の基本的な考えは、static でないデータメンバが (その class 内で) 宣言されたところで初期化されることを許容する、というものだ。 従って、コンストラクタは、実行時に初期化が必要となった時に初期化子を呼び出すことができる。 以下を考えよ:

	class A {
	public:
		int a = 7;
	};
これは以下と等価だ:

	class A {
	public:
		int a;
		A() : a(7) {}
	};
これでタイピングをちょっとだけ削減できるが、本当の利点は class 内に複数のコンストラクタが存在する場合に現れる。 全てのコンストラクタが、あるメンバを同じように初期化するのはよくあることだ:

	class A {
	public:
		A(): a(7), b(5), hash_algorithm("MD5"), s("Constructor run") {}
		A(int a_val) : a(a_val), b(5), hash_algorithm("MD5"), s("Constructor run") {}
		A(D d) : a(7), b(g(d)), hash_algorithm("MD5"), s("Constructor run") {}
		int a, b;
	private:
		HashingFunction hash_algorithm;  // 全ての A のインスタンスに対して適用する暗号ハッシュ
		std::string s;                   // オブジェクトのライフサイクルを示す状態文字列
	};
hash_algorithms にはそれぞれ唯一の既定値があるという事実が大量のコードの中に埋もれてしまい、メンテナンスで容易に問題になり得る。 代わりに、データメンバの初期化を取り除くことができる:

	class A {
	public:
		A(): a(7), b(5) {}
		A(int a_val) : a(a_val), b(5) {}
		A(D d) : a(7), b(g(d)) {}
		int a, b;
	private:
		HashingFunction hash_algorithm{"MD5"};  // 全ての A のインスタンスに対して適用する暗号ハッシュ
		std::string s{"Constructor run"};       // オブジェクトのライフサイクルを示す状態文字列
	};
メンバが class 内初期化子とコンストラクタの両方で初期化される場合、コンストラクタの方だけで初期化される (既定を「オーバーライド」する)。 従って、より単純化することができる:

	class A {
	public:
		A() {}
		A(int a_val) : a(a_val) {}
		A(D d) : b(g(d)) {}
		int a = 7;
		int b = 5;
	private:
		HashingFunction hash_algorithm{"MD5"};  // 全ての A のインスタンスに対して適用する暗号ハッシュ
		std::string s{"Constructor run"};       // オブジェクトのライフサイクルを示す状態文字列
	};

以下も参照。


継承コンストラクタ

通常のスコープ規約が class メンバに対して適用される、という事実に混乱する人達が時々いる。 特に、基底 class のメンバが派生 class のメンバとして同じスコープに存在しない場合だ:

	struct B {
		void f(double);
	};

	struct D : B {
		void f(int);
	};

	B b;   b.f(4.5);	// 大丈夫
	D d;   d.f(4.5);	// びっくり: 引数 4 で f(int) を呼び出す
C++98 では、基底 class から派生 class へオーバーロードされる関数を「取込む」ことができた:

	struct B {
		void f(double);
	};

	struct D : B {
		using B::f;     // B からこのスコープへ全ての f() を取込む
		void f(int);    // 新たな f() を追加
	};

	B b;   b.f(4.5);	// 大丈夫
	D d;   d.f(4.5);	// 大丈夫: B::f(double) である D::f(double) を呼び出す
著者はかつて「ほとんど歴史上の事故で、コンストラクタではこの using の用法が通常のメンバ関数と同様には機能しない」と言ったことがある。 C++11 は以下の支援機能を提供する:

	class Derived : public Base { 
	public: 
		using Base::f;    // Base の f を Derived のスコープへ取込む -- C++98 でも動く
		void f(char);     // 新たな f を提供 
		void f(int);      // この f は Base::f(int) よりも優先 

		using Base::Base; // Base のコンストラクタを Derived のスコープへ取込む -- C++11 のみ
		Derived(char);    // 新たなコンストラクタの提供 
		Derived(int);     // このコンストラクタは Base::Base(int) よりも優先 
		// ...
	}; 

そうした場合、初期化が必要な新しいメンバ変数を定義している派生 class の継承コンストラクタで、自分の足を撃ってしまうことがある:


	struct B1 {
		B1(int) { }
	};

	struct D1 : B1 {
		using B1::B1;	// 暗黙的な D1(int) の宣言
		int x;
	};

	void test()
	{
		D1 d(6);	// おっと: d.x が初期化されない
		D1 e;		// エラー: D1 に既定のコンストラクタがない
	}
メンバ初期化子を使って自分の足を撃たないようにできる:

	struct D1 : B1 {
		using B1::B1;	// 暗黙的な D1(int) の宣言
		int x{0};	// メモ: x は初期化される
	};

	void test()
	{
		D1 d(6);	// d.x はゼロ
	}

以下も参照。


静的 (コンパイル時) アサーション -- static_assert

静的 (コンパイル時) アサーションは定数式と文字列リテラルからなる:

	static_assert(式,文字列);
コンパイラは式を評価し、その結果が偽 (つまりアサーションが失敗) の場合、文字列をエラーメッセージとして出力する。 例えば:

	static_assert(sizeof(long)>=8, "64-bit コードの生成がこのライブラリには必要");
	struct S { X m1; Y m2; };
	static_assert(sizeof(S)==sizeof(X)+sizeof(Y),"予期しないパディングが S 中に存在");
static_assert はプログラムとその処理について、コンパイラによる明示的な前提条件を置く際に役に立つだろう。 static_assert はコンパイル時に評価するため、実行時の値に依存する前提条件をチェックできないことに注意すること。 例えば:

	int f(int* p, int n)
	{
		static_assert(p==0,"p is not null");	// エラー: static_assert() 式が定数式でない
		// ...
	}
(代わりに、テストして失敗した場合に例外を投げるようにすること)

以下も参照。


long long -- 更に大きい整数

少なくとも 64 ビットの整数型。 例えば:

	long long x = 9223372036854775807LL;
いや、long long long 型はないし、long 型を short long long と綴ることもできない。

以下も参照。


nullptr -- ナルポインタ定数

nullptr はナルポインタを意味するリテラルである; これは整数ではない:

	char* p = nullptr;
	int* q = nullptr;
	char* p2 = 0;		// 0 も従来の通り使用可能で、p==p2

	void f(int);
	void f(char*);

	f(0);			// f(int) を呼び出す
	f(nullptr);		// f(char*) を呼び出す

	void g(int);
	g(nullptr);		// エラー: nullptr は int ではない
	int i = nullptr;	// エラー: nullptr は int ではない

以下も参照。


戻り値型の後方宣言

以下を考えよ:

	template<class T, class U>
	??? mul(T x, U y)
	{
		return x*y;
	}
この戻り値型を何と書けば良いだろう? もちろん答えは「x*y の型」なのだが、それをどうやって書けば良いかということだ。 最初の考えは、「decltype」を使うことだ:

	template<class T, class U>
	decltype(x*y) mul(T x, U y) // スコープ問題!
	{
		return x*y;
	}
xy がスコープ中にないため、これはうまくいかない。 しかしながら、こう書くことならできる:

	template<class T, class U>
	decltype(*(T*)(0)**(U*)(0)) mul(T x, U y)	// 醜い! しかも間違いやすい
	{
		return x*y;
	}
おまけに、この「美しくない」呼び出し方は、過度に格式ばっている。

解は、戻り値型を引数の後に記述することだ:


	template<class T, class U>
	auto mul(T x, U y) -> decltype(x*y)
	{
		return x*y;
	}
ここで、「戻り値型を導出するか、後で指定する」ことを意味する auto 表記を用いた。

後置表記は template と型導出を主目的とするものではなく、スコープ問題を解決するためのものだ。


	struct List {
		struct Link { /* ... */ };
		Link* erase(Link* p);	// p を削除し、p の直前のリンクを返却
		// ...
	};

	List::Link* List::erase(Link* p) { /* ... */ }
最初の List:: が必須である理由は、List のスコープが二番目の List:: の後から始まるためだ。 より良い書き方:

	auto List::erase(Link* p) -> Link* { /* ... */ }
これで Link の明示的な修飾が不要になる。

以下も参照。


template の別名 (以前は「template typedef」として知られていた)

いくつかの template 引数が固定 (束縛) されていることを除けば「他の template とほとんど同じ」template を書くにはどうすればいいだろう? 以下を考えよ:

	template<class T>
	using Vec = std::vector<T,My_alloc<T>>;	// 自前アロケータを使った標準の vector

	Vec<int> fib = { 1, 2, 3, 5, 8, 13 }; // My_alloc を使った要素の割り当て

	vector<int,My_alloc<int>> verbose = fib; // verbose と fib は同じ型
このキーワード using で「右辺の型を参照する名前」を記述するという線形な表記ができる。 著者達は、伝統的でひねくれた typedef で解決しようとしてはみたのだが、もっと不明瞭な文法に我慢しない限り、完全で首尾一貫した解決を得るには至らなかった。

特殊化も動作する (特殊化したものを別名に取ることはできるが、別名を特殊化することはできない)。 例えば:


	template<int>
	struct int_exact_traits {	// 考え: int_exact_trait<N>::type は正確に N bit の型
		typedef int type;
	};

	template<>
	struct int_exact_traits<8> {
		typedef char type;
	};

	template<>
	struct int_exact_traits<16> {
		typedef char[2] type;
	};

	// ...

	template<int N>
	using int_exact = typename int_exact_traits<N>::type;	// 表記上の利便性のため、別名を定義

	int_exact<8> a = 7;	// int_exact<8> は 8 bit の整数
template に関連する重要性に加えて、型の別名は異なる (そして著者に言わせればより良い) 文法として通常の型の別名にも使うことができる:

typedef void (*PFD)(double);	// C スタイル
using PF = void (*)(double);	// using + C スタイルの型
using P = [](double)->void;	// using + 後置戻り値型

以下も参照。


可変個引数 template

解決したい問題: 最後の問題が鍵となる: tuple のことを考えれば良いのだ! 一般的な tuple を作ったり、アクセスしたりできるなら、残りの問題も同様に解決できる。

この例 (「可変個引数 template の簡単な紹介」(参考文献を参照) から引用) は、汎用的でタイプセーフな printf() の実装だ。 実際に使うなら boost::format の方が良いだろうが、まあ以下を考えよ:


	const string pi = "円周率";
	const char* m = "%sの値は大体 %g (%s 以外では)。\n";
	printf(m,  pi, 3.14159,  "Indiana");

一番簡単なパターンの printf() は、書式文字列だけの場合なので、最初はそれから扱おう:

	void printf(const char* s)	
	{
		while (s && *s) {
		 	if (*s=='%' && *++s!='%')	// 他の引数を渡すことを意図していなかったか、念のため確認
							// 書式文字列中の %% は % の意味
			throw runtime_error("無効な書式: 引数がない");
			std::cout << *s++;
		}
	}

次に、引数が加わった printf() を扱わなければならない:

	template<typename T, typename... Args>		// "..." に注目
	void printf(const char* s, T value, Args... args)	// "..." に注目
	{
		while (s && *s) {
			if (*s=='%' && *++s!='%') {	// 書式指定子 (%% は無視)
				std::cout << value;		// 最初の書式でない引数
				return printf(++s, args...); 	// 最初の引数を「剥ぎ取る」
			}
			std::cout << *s++;
		}
		throw std::runtime error("余分な引数が printf に渡された");
	}

このコードは単純に最初の書式でない引数を「剥ぎ取」って、自分自身を再帰的に呼び出して行き、 書式でない引数がなくなった時点で、最初の (単純な) printf (上述) を呼び出す。 これは、言わばコンパイル時に行われる、通常の関数型プログラミングだ。 << のオーバーロードが書式文字列中の (間違っているかも知れない)「ヒント」に取って代わっていることに注意されたい。

Args... は、いわゆる『引数パック』を定義している。 これは基本的に (型/値) ペアの順列で、その先頭から引数を『剥ぎ取る』ことができる。 printf() が引数一つで呼び出された場合は、最初の定義 (printf(const char*)) が選択される。 printf() が二つ以上の引数で呼び出された場合は、二つ目の定義 (printf(const char*, T value, Args... args)) が選択され、その第一引数は s、第二引数は value、そして残り全部は (それが何だろうと) 引数パック args に詰め込まれていて、後で使用することができる。 以下の呼び出しでは、


	printf(++s, args...); 
引数パック args が展開されるので、次の引数は value として使えるようになる。 これは args が空になる (即ち最初のバージョンの printf() が呼び出される) まで続く。

もし関数型プログラミングに慣れているのなら、これはごく普通の書き方だと思うだろう。 そうでないなら、もうちょっと技術的な手がかりとなる例をお見せしよう。 まず、単純な可変個引数 template 関数 (上記の printf() のような) を宣言して使うことができる:


	template<class ... Types> 
		void f(Types ... args);	// 可変個引数 template 関数
					// (任意の型の可変個の引数を取る関数)
	f();	 	// OK: 引数なし
	f(1);	 	// OK: 引数一つ: int
	f(2, 1.0); 	// OK: 引数二つ: int と double
以下のように可変個型を作ることができる:
	
	template<typename Head, typename... Tail>
	class tuple<Head, Tail...>
		: private tuple<Tail...> {	// ここで再帰呼び出し
				// 基本的に、tuple はその先頭 (一番目の (型/値) ペア) に格納され 
				// その後 (残りの (型/値) ペア) の tuple から派生する。
				// 型の中に埋め込まれている型は、データとして格納されていないことに注意
		typedef tuple<Tail...> inherited;
	public:
		tuple() { }	// 既定: 空の tuple

		// 別々の引数から tuple を構築:
		tuple(typename add_const_reference<Head>::type v, typename add_const_reference<Tail>::type... vtail)
			: m_head(v), inherited(vtail...) { }

		// 別の tuple から tuple を構築:
		template<typename... VValues>
		tuple(const tuple<VValues...>& other)
		:	 m_head(other.head()), inherited(other.tail()) { }

		template<typename... VValues>
		tuple& operator=(const tuple<VValues...>& other)	// 代入
		{
			m_head = other.head();
			tail() = other.tail();
			return *this;
		}

		typename add_reference<Head>::type head() { return m_head; }
		typename add_reference<const Head>::type head() const { return m_head; }

		inherited& tail() { return *this; }
		const inherited& tail() const { return *this; }
	protected:
		Head m_head;
	}
以上の定義から、tuple を作ること (やコピーしたり操作すること) ができる:

	tuple<string,vector<int>,double> tt("hello",{1,2,3,4},1.2);
	string h = tt.head();	// "hello"
	tuple<vector<int>,double> t2 = tt.tail();	// {{1,2,3,4},1.2};
これら全ての型を完全に扱うのは少し長ったらしくなりがちなので、標準ライブラリの make_tuple() を用いて、引数型を導出させる:

	template<class... Types>
	tuple<Types...> make_tuple(Types&&... t)	// この定義は多少単純化 (標準の 20.5.2.2 を参照)
	{
		return tuple<Types...>(t...);
	}
	
	string s = "Hello";
	vector<int> v = {1,22,3,4,5};
	auto x = make_tuple(s,v,1.2);

以下も参照:


統一された初期化構文と動作

C++ は、オブジェクトの型と初期化に応じて、初期化の方法を複数提供している。 使い方を間違えると、エラーにびっくりしたり、エラーメッセージが分り難かったりすることがある。 以下を考えよ:

	string a[] = { "foo", " bar" };		// ok: 配列変数の初期化
	vector<string> v = { "foo", " bar" };	// エラー: 集合体でない vector に対する初期化リスト
	void f(string a[]);
	f( { "foo", " bar" } );			// 文法エラー: ブロックを引数にしている
それから、

	int a = 2;		// 「代入形式」
	int aa[] = { 2, 3 };	// リストを使った代入形式
	complex z(1,2);		// 「関数形式」の初期化
	x = Ptr(y);		// 「関数形式」の変換 / キャスト / 構築
それに、

	int a(1);	// 変数定義
	int b();	// 関数宣言
	int b(foo);	// 変数定義か関数宣言
初期化の規約を憶えたり、どの方法が一番良いか選ぶのが難しくなりがちだ。

C++11 の解は {} 初期化リストを全ての初期化で可能にすることである:


	X x1 = X{1,2}; 
	X x2 = {1,2}; 	// この = がなくても良い
	X x3{1,2}; 
	X* p = new X{1,2}; 

	struct D : X {
		D(int x, int y) :X{x,y} { /* ... */ };
	};

	struct S {
		int a[3];
		S(int x, int y, int z) :a{x,y,z} { /* ... */ }; // 古い問題の解決
	};
重要なことは、X{a} が同じ値を全ての文脈で構築するということであり、故に、{} 初期化は、それが合法である全ての場所で同一の結果を与える。 例えば:

	X x{a}; 
	X* p = new X{a};
	z = X{a};	// キャストとして使用
	f({a});		// (X 型の) 関数の引数
	return {a};	// 関数の戻り値 (関数の戻り値型は X)

以下も参照。


右辺値リファレンス

左辺値 (代入の左辺として使うことができる) と右辺値 (代入の右辺として使うことができる) の区別は Christopher Strachey (C++ の遠い先祖である CPL と表示的意味論の父) に遡る。 C++ において、非 const リファレンスは左辺値を指すことができ、const リファレンスは左辺値も右辺値も指すことができるが、非 const 右辺値を指す術はない。 これは、新しい一時的な値を使う前に、それオブジェクトが破棄されてしまうというミスを防ぐためだ。 例えば:

	void incr(int& a) { ++a; }
	int i = 0;
	incr(i);	// i は 1 になる
	incr(0);	// エラー: 0 は左辺値でない
もし incr(0) が許されたなら、誰にも操作できない一時的な値が加算されてしまう。 あるいは - 更に拙いことに - 0 が1 になってしまう。 後者は馬鹿げた話のように聞こえるが、値 0 を持つアドレスを保持していた初期の Fortran コンパイラで、実際にそういうバグがあったのだ。

ここまでは良いとして、以下を考えよ。


	template<class T> swap(T& a, T& b)		// 「古いスタイルの swap」
	{
		T tmp(a);	// ここで a のコピーが二つ
		a = b;		// ここで b のコピーが二つ
		b = tmp;	// ここで tmp (つまり a) のコピーが二つ
	} 
T が、string や vector のように要素のコピーのコストが高い型である場合、swap のコストも高くなってしまう (標準ライブラリでは、これをうまく扱うために string や vector の swap() を特殊化している)。 ちょっと変だと思わないか? 我々は、別にコピーを作りたいわけではなく、ちょっと ab、そして tmp の値を動かしたいだけなのだ。

C++11 では、引数をコピーでなく移動させる「移動コンストラクタ」と「移動代入」を定義することができる:


	template<class T> class vector {
		// ...
		vector(const vector&);	 		// コピーコンストラクタ
		vector(vector&&);	 		// 移動コンストラクタ
		vector& operator=(const vector&);	// コピー代入
		vector& operator=(vector&&);		// 移動代入
	};	// メモ: 移動コンストラクタと移動代入は、非 const && を引数に取る
		// これらはその引数に書込でき、そして通常は書込に使う
&& が「右辺値リファレンス」であることを示す。 右辺値リファレンスは右辺値を指すことができる (が、左辺値を指すことはできない):

	X a;
	X f();
	X& r1 = a;		// r1 は a を指す (左辺値)
	X& r2 = f();		// エラー: f() は右辺値; 指すことはできない

	X&& rr1 = f();	// 大丈夫: rr1 は一時的な値を指す
	X&& rr2 = a;	// エラー: 指そうとしている a は左辺値
移動代入の背景にある考えは、コピーを行うことを代替しようというもので、単純に転送先の表現を安価な既定値で置き換えようというものだ。 例えば、s1=s2 の文字列で移動代入を使うと s2 の文字のコピーが必要なくなる; 代わりに、s1s2 の文字を自分自身の文字として扱い、元の文字は削除される (s2 に残るかも知れないが、破壊されるだけだろう)。

どうすれば単純に代入元から移動させてよいか判断できるだろう? コンパイラにこう伝えればよい:


	template<class T> 
	void swap(T& a, T& b)	// 「完全な swap」(ほとんど)
	{
		T tmp = move(a);	// a を破棄してよい
		a = move(b);		// b を破棄してよい
		b = move(tmp);		// tmp を破棄してよい
	}
move(x) は「x を右辺値として扱ってよい」という意味だ。 もし move()rval() を呼び出しているならこれだけで改善されるだろうが、これまで move() は何年も使われてきた。 move() template 関数を C++11 で右辺値リファレンスを使うように書き直せばよいのだ (「簡単な紹介」を参照)。

右辺値リファレンスは完全な転送として使うこともできる。

C++11 標準ライブラリでは、全てのコンテナで、移動コンストラクタと移動代入演算子が提供され、insert()push_back() のように新しい要素を追加する操作で右辺値リファレンスを使うバージョンが追加される。 最終的に、コピーが減ることで、ユーザの預り知らないうちに標準コンテナとアルゴリズムの性能が向上する。

以下も参照。


union (一般化)

C++98 (それ以前の C++ でも同様) では、ユーザ定義のコンストラクタ、デストラクタ、代入を持つメンバは union のメンバになれなかった:

	union U {
	int m1;
	complex<double> m2;	// エラー (変): complex にはコンストラクタがある
	string m3;		// エラー (変ではない): string にはコンストラクタ、コピー、デストラクタで
				// 維持しなくてはならない重要な不変条件がある
};
特に、

	U u;			// 一体どのコンストラクタ?
	u.m1 = 1;		// int メンバへの代入
	string s = u.m3;	// 失敗: string メンバから読み込んでしまった
明らかに、あるメンバに書き込んで別のメンバを読むことは非合法であるが、それでもこうしてしまうのだ (普通は間違いで)。

C++11 は union の制限を修正して、より多くのメンバ型を実現可能にした; 特に、コンストラクタとデストラクタのあるメンバ型を許容するようになった。 また、峻別された union の構築を奨励することで、よりフレキシブルになった union がエラーになりにくいように制限を追加した。

union のメンバ型には以下の制限がある:

例えば:

	union U1 {
		int m1;
		complex<double> m2;	// ok
	};
	
	union U2 {
		int m1;
		string m3;	// ok
	};
これはエラーになりがちに見えるが、新しい制限が救ってくれる。 特に:

	U1 u;		// ok
	u.m2 = {1,2};	// ok: complex メンバへの代入
	U2 u2;		// エラー: string のデストラクタが、delete されるべき U2 のデストラクタになる
	U2 u3 = u2;	// エラー: string のコピーコンストラクタが、delete されるべき U2 のコピーコンストラクタになる
U2 は、どのメンバが使われているか追跡するものを構造体の中に埋め込まれない限り、基本的に使い道がない。 従って、以下のように union を峻別しよう:

	class Widget {	// union として表現された三つの実装
	private:
		enum class Tag { point, number, text } type;	// 峻別
		union {		// 表現
			point p;	// point にはコンストラクタがある
			int i;
			string s;	// string には既定コンストラクタ、コピー演算子、デストラクタがある
		};
		// ...
		Widget& operator=(const Widget& w) 	// string 版のために必要
		{
			if (type==Tag::text && w.type==Tag::text) {
				s = w.s;		// 通常の string 代入
				return *this;
			}

			if (type==Tag::text) s.~string();	// 破棄 (明示的な!)

			switch (w.type) {
			case Tag::point: p = w.p; break;	// 通常のコピー
			case Tag::number: i = w.i; break;
			case Tag::text: new(&s)(w.s); break;	// 配置 new
			}
			type = w.type;
			return *this;
		}
	};
以下も参照:


POD (一般化)

POD (「Plain Old Data」) は C の構造体のように操作できるものであり、例えば、memcpy() でコピーしたり、memset() で初期化したりできる。 C++98 では、POD の実際の定義は構造体の定義に使われる言語機能の使用制限に基づいていた:
 
	struct S { int a; };	// S は POD
	struct SS { int a; SS(int aa) : a(aa) { } }; // SS は POD でない
	struct SSS { virtual void f(); /* ... */ };
C++11 では、S と SS は「標準レイアウト型」(又の名を POD) になる。 なぜなら SS には実際のところ何の「魔法」も掛かっていないからだ: コンストラクタはレイアウトに何の影響も与えず (従って memcpy() はうまく動作する)、単に初期化の規則を定めているだけだ (memset() は不変性を強制できないため、この点ではよろしくない)。 しかしながら、SSS には vptr があるから「plain old data」のようにはならない。 C++11 は、何を POD として扱うかという様々な技術的観点に基づいて、POD、自明にコピー可能な型、自明な型、標準レイアウト型を定義している。 POD は以下のように再帰的に定義される。 C++11 の POD に関して最も重要な点は、コンストラクタを追加したり削除したりしてもレイアウトや性能には影響しないということだ。

以下も参照:


生の文字列リテラル

多くの場合、例えば、標準 regex ライブラリで正規表現を書くような場合、バックスラッシュ (\) がエスケープ文字だという現実は迷惑の種だった (正規表現ではバックスラッシュが文字クラスを表す特殊文字の先頭で使われるため)。 バックスラッシュ一文字を挟んでいる二つの文字を表現するパターン (\w\\\w) をどう書けばいいか考えよ:

	string s = "\\w\\\\\\w";	// 多分正しい
バックスラッシュ文字は、正規表現の中ではバックスラッシュ二つで表されることに注意すること。 基本的に、「生の文字列リテラル」は一つのバックスラッシュでバックスラッシュを表す文字列リテラルであり、そのため、上記の例は以下のようになる:

	string s = R"(\w\\\w)";	// 間違いなく正しい
生の文字列の動機となる例として、元々の提案にあった、

	"('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|"	// 五つのバックスラッシュは正しいか否か?
								// 熟練者ですら容易に混乱する。 
が、良い例だ。 R"(...)" の表現の方が「生の」"..." より少し分かりやすいが、エスケープ文字が使えないと「生+α」が必要になることがある。 生の文字列中にクォートを混ぜるにはどうすればよいだろう? クォートが ) で始まらない場合は簡単だ:

	R"("quoted string")"	// 文字列は "quoted string"
では、)" の文字の並びを生の文字列にしたい場合はどうすればよいだろう? 幸いなことに、これは滅多に起きない問題だが、("...") は既定の区切りペアに過ぎない。 "(...)" 中の (...) の先頭と末尾に区切りを追加することもできる。 例えば、

	R"***("quoted string containing the usual terminator (")")***"	// 文字列は "quoted string containing the usual terminator (")"
) の後の文字の並びは ( の前の並びと一致しなくてはならない。 この方法で (ほとんど) 任意の複雑なパターンに対処することができる。

生の文字列中の最初の R にはエンコーディング接頭辞を付けてもよい: u8uUL。 例えば、u8R"(fdfdfa)" は UTF-8 文字列リテラルだ。

以下も参照。


ユーザ定義リテラル

C++ は組込型向けに様々なリテラルを提供している (2.14 リテラル):

	123	// int
	1.2	// double
	1.2F	// float
	'a'	// char
	1ULL	// unsigned long long
	0xD0	// 十六進 unsigned
	"as"	// 文字列
しかしながら、C++98 には、ユーザ定義型用のリテラルはなかった。 これは悩みの種になりかねないし、更に、ユーザ定義型が組込型と同様にサポートされるべきだという原則に反するように思われる。 特に要望が多いのは以下のような場合だ:

	"Hi!"s			// string、『ゼロ終端の char 配列』ではない
	1.2i			// 虚数
	123.4567891234df	// 十進浮動小数 (IBM)
	101010111000101b	// 二進数
	123s			// 
	123.56km		// マイルではない! (単位)
	1234567890123456789012345678901234567890x	// 拡張精度
C++11 は、お望みの型について、接尾語を追加することでリテラルになるリテラル演算子により、『ユーザ定義リテラル』をサポートする。 例えば:

	constexpr complex<double> operator "" i(long double d)	// 虚数リテラル
	{
		return {0,d};	// complex<double > はリテラル型
	}

	std::string operator""s (const char* p, size_t n)	// std::string リテラル
	{
		return string(p,n);	// フリーストアの割り付けが必要
	}
コンパイル時評価を可能にする constexpr を使用していることに注意。 ここまで来れば、以下のように書くことができる。

	template<class T> void f(const T&);
	f("Hello");	// const char* へのポインタを渡す
	f("Hello"s);	// (5 文字の) string オブジェクトを渡す
	f("Hello\n"s);	// (6 文字の) string オブジェクトを渡す

	auto z = 2+1i;	// complex<double>(2,1)
基本的な (実装の) 考えは、何がリテラルになり得るかパースした後、常にコンパイラが接尾語をチェックするというものだ。 ユーザ定義リテラルの仕組みで、新しい接尾語をユーザに指定させ、ユーザがリテラルで何かする前に何をすべきか示すことが単純に可能になる。 組込リテラル接尾語の意味やリテラル引数の文法再定義することはできない。 リテラル演算子は、その (先行する) リテラルを『処理済の』形式 (新しい接尾語が定義されていない場合に渡されるはずの値) か、『元々の』形式 (文字列として) で要求することができる。

『元々の』文字列を得るには、単に一つの const char* 引数を要求すればよい:


	Bignum operator"" x(const char* p)
	{
		return Bignum(p);
	}

	void f(Bignum);
	f(1234567890123456789012345678901234567890x);
ここで、C 形式の文字列 "1234567890123456789012345678901234567890"operator"" x() に渡される。 数字を明示的に文字列にしていない点に注意すること。

ユーザ定義リテラルをつくる接尾語には四種類ある。

文字列リテラルについては const char* だけの (長さがない) 引数をとるリテラル演算子をつくれないことに注意すること。 例えば:

	string operator"" S(const char* p);		// 警告: 期待したようには動かない

	"one two"S;	// エラー: 適用可能なリテラル演算子がない

この論拠は、『異なる種類の文字列』を持とうとするなら、いずれにせよほとんどの場合に文字数を知りたいだろうということだ。

接尾語は短くなる傾向が強いだろうから (例えば、string の s、虚数の i、メートルの m、拡張数の x 等)、異なる用法が簡単に衝突してしまう。 衝突を避けるには名前空間を使う。


	namespace Numerics { 
		// ...
		class Bignum { /* ... */ }; 
		namespace literals { 
			operator"" X(char const*); 
		} 
	} 

	using namespace Numerics::literals; 

以下も参照:


アトリビュート

『アトリビュート』は、任意の追加情報やベンダ固有情報 (例えば、__attribute____declspec#pragma のように) をソースコードに追加するための雑多な支援機能何かを提供することを目的とした新しい標準構文だ。 C++11 のアトリビュートは、コードのどこに書いてもよく、常に直前の構文要素を修飾する、という点で既存の文法とは異なっている。 例えば:

	void f [[ noreturn ]] ()	// f() は決して return しない
	{
		throw "error"; 	// OK
	}

	struct foo* f [[carries_dependency]] (int i);	// 最適化のヒント
	int* g(int* x, int* y [[carries_dependency]]);

上記の通り、アトリビュートは二重カギ括弧 [[ ... ]] の中に置かれる。 noreturnalign は標準で定義される二つのアトリビュートだ; アトリビュートは言語の方言として使われるのではないか、というもっともらしい危惧がある。 アトリビュートは、プログラムの意味に影響を与えず、エラーを検知したり ([[noreturn]] のように)、最適化を支援する ([[carries_dependency]] のように) 用途でだけ使われるべきだ。

アトリビュートの用途として計画されているものの中に OpenMP のサポート向上がある。 例えば:


	for [[omp::parallel()]] (int i=0; i<v.size(); ++i) {
		// ...
	}
このように、アトリビュートを修飾することもできる。

以下も参照:


ラムダ

ラムダ式は関数オブジェクトを宣言するための仕組みだ。 ラムダの主な用途は、何らかの関数が行う単純な操作を指定することだ。 例えば:
 
	vector<int> v = {50, -10, 20, -30};

	std::sort(v.begin(), v.end());	// 既定の sort
	// ここで、 v は { -30, -10, 20, 50 } になる

	// 絶対値による sort:
	std::sort(v.begin(), v.end(), [](int a, int b) { return abs(a)<abs(b); });
	// ここで、 v は { -10, 20, -30, 50 } になる
引数 [](int a, int b) { return abs(a)<abs(b); } が「ラムダ」 (または「ラムダ関数」や「ラムダ式」とも) であり、与えられた二つの整数の引数 ab の絶対値を比較した結果を返す。

ラムダ式は、自身が使われているスコープ内の局所変数にアクセスすることもできる:


	void f(vector<Record>& v)
	{
		vector<int> indices(v.size());
		int count = 0;
		generate(indices.begin(),indices.end(),[&count](){ return count++; });

		// Record の項目 name 順に indices を並べる:
		std::sort(indices.begin(), indices.end(), [&](int a, int b) { return v[a].name<v[b].name; });
		// ...
	}
人によってはこれを「マジでカッコいい!」と考えるかも知れないが、人によっては危険で分かりにくいコードを書く方法だと思うかも知れない。 個人的には、どちらも正しいと思う。

[&] は、リファレンスによって渡される局所変数を指定する「キャプチャリスト」である。 v だけを「キャプチャ」したいのなら [&v] と書けばよい。 v を値で受け取りたい場合は、[=v] と書く。 何もキャプチャしない場合は []、全部リファレンスでキャプチャする場合は [&]、全部を値でキャプチャする場合は [=] となる。

動作が一般的でも単純でもないのであれば、著者としては名前付きの関数オブジェクトか関数の使用をお勧めする。 例えば、上記の例は以下のように書くこともできる:


	void f(vector<Record>& v)
	{
		vector indices(v.size());
		int count = 0;
		generate(indices.begin(),indices.end(),[&](){ return ++count; });

		struct Cmp_names {
			const vector<Record>& vr;
			Cmp_names(const vector<Record>& r) :vr(r) { }
			bool operator()(int a, int b) const { return vr[a].name<vr[b].name; }
		};

		// Record の項目 name 順に indices を並べる:
		std::sort(indices.begin(), indices.end(), Cmp_names(v));
		// ...
	}
この Record の name 項目の比較のように、ごく小さい関数では、関数オブジェクトで書いた方が冗長になるが、生成されるコードは多分同じだろう。 C++98 では、このような関数オブジェクトを template 引数にするために非局所化する必要があったが、C++11 ではもうその必要はなくなった

ラムダを定義するには、以下のものを与える必要がある。

以下も参照:


template 引数としての局所 class

C++98 では、局所型や無名型は template 引数として使用できなかった。 これは足かせになることがあるため、C++11 ではこの制限を取り除いた:

	void f(vector<X>& v)
	{
		struct Less {
			bool operator()(const X& a, const X& b) { return a.v<b.v; }
		};
		sort(v.begin(), v.end(), Less());	// C++98: エラー: Less は局所型
							// C++11: ok
	}
C++11 では、ラムダ式 を用いて以下のように書くこともできる:

	void f(vector<X>& v)
	{
	 	sort(v.begin(), v.end(), 
			[] (const X& a, const X& b) { return a.v<b.v; }); // C++11 
	}
名前を付けるということは、ドキュメント化に大変便利になり得るし、良い設計を促すことになるという点も意識しておく価値がある。 また、非局所 (名前が必要な) エンティティであれば再利用することもできる。

C++11 は無名型の値を template 引数として使用することも許容する:


	template<typename T> void foo(T const& t){}
	enum X { x };
	enum { y };

	int main()
	{
		foo(x);		// C++98: ok; C++11: ok
		foo(y);		// C++98: エラー; C++11: ok
		enum Z { z };
		foo(z);		// C++98: エラー; C++11: ok 
	}
以下も参照:


noexcept -- 例外の伝搬の禁止

もし、ある関数が例外を投げられない、または関数から投げられる例外を処理できるようにプログラムが書かれていない場合は、関数を noexcept と宣言することができる。 例えば:

	extern "C" double sqrt(double) noexcept;	// 決して例外を投げない

	vector<double> my_computation(const vector<double>& v) noexcept	// メモリ不足に対応するようにはできてないよ
	{
		vector<double> res(v.size());	// 例外を投げるかも
		for(int i; i<v.size(); ++i) res[i] = sqrt(v[i]);
		return res;
	}
noexcept と宣言された関数が例外を投げると (つまり、その例外が noexcept 関数から抜け出そうとすると)、そのプログラムは (terminate() の呼出によって) 終了する。 terminate() の呼出では、オブジェクトが正常な状態であることをアテにできない (すなわち、デストラクタが起動されている保証や、スタックが巻き戻されている保証はないし、問題が起きなかったかのようにプログラムを再開できる可能性はゼロだ)。 これはよくよく考えられた上でのことで、noexcept を単純で、乱暴だが、非常に効率的な (昔の動的な throw() よりはるかに効率的だ) 仕組みにしたのだ。

ある関数を条件付きで noexcept にすることもできる。 例えば、あるアルゴリズムで用いる template 引数が noexcept の場合に限り、noexcept と指定することができる:


	template<class T>
	void do_f(vector<T>& v) noexcept(noexcept(f(v.at(0))))	// f(v.at(0)) が可能なら例外を投げてよい
	{
		for(int i; i<v.size(); ++i)
			v.at(i) = f(v.at(i));
	}
ここで、最初の noexcept は演算子として使用した: noexcept(f(v.at(0)))f(v.at(0)) が例外を投げられない場合、つまり f()at()noexcept の場合に真となる。

noexcept() 演算子は定数式であり、その演算対象が評価されることはない。

一般的な noexcept 宣言の形式は noexcept(式) と、noexcept(true) の単純な省略形である『noexcept』だ。 ある関数の全ての宣言は noexcept の仕樣に関して互換でなければならない。

デストラクタは例外を投げるべきではない; 自動生成されたデストラクタは、その class の全てのメンバが noexcept のデストラクタを持つ場合、暗黙的に noexcept となる (そのコードの内容とは関係なく)。

例外を投げる移動操作は良くないアイディアの典型なので、可能ならどこでもそれらを noexcept と宣言すること。 自動生成されたコピーや移動操作は、その class の全てのメンバが noexcept のデストラクタを持つ場合、暗黙的に noexcept となる。

noexcept は、性能を向上させ要件を明確化させるために標準ライブラリの中で広範かつ体系的に利用されている。 以下も参照:


アラインメント

時々、生のメモリを操作するコードを書いている時は特に、割り付けのアラインメントを指定する必要がある。 例えば:

	alignas(double) unsigned char c[1024];	// 文字配列、double 境界に整列させる
	alignas(16) char[100];			// 16 バイト境界に整列させる
その演算対象 (型でなければならない) のアラインメントを返す alignof 演算子もある。 例えば、

	constexpr int n = alignof(int);		// int は n バイト境界に割り付けられる

以下も参照:


オーバーライドの制御: override

派生 class の関数で基底 class の関数をオーバーライドするのに、特別なキーワードやアノテーションは必要ない。 例えば:

	struct B {
		virtual void f();
		virtual void g() const;
		virtual void h(char);
		void k();	// 仮想関数ではない
	};

	struct D : B {
		void f();	// B::f() をオーバーライド
		void g();	// B::g() をオーバーライドしない (型が間違っている))
		virtual void h(char);	// B::h() をオーバーライド
		void k();	// B::k() をオーバーライドしない (B::k() は仮想関数でない)
	};
これは混乱の元だし (プログラマは何を意図していたのだろうか?) コンパイラが疑わしいコードに対して警告を発するかどうかで問題になる。 例えば、 プログラマがオーバーライドの意図をより明確にできるように「文脈キーワード」override ができた:

	struct D : B {
		void f() override;	// OK: B::f() をオーバーライド
		void g() override;	// エラー: 型が間違っている
		virtual void h(char);	// B::h() をオーバーライド、警告されるだろう
		void k() override;	// エラー: B::k() は仮想関数でない
	};
override とマークされた宣言は、その関数をオーバーロードした時に限り有効になる。 h() の問題が検出される保証はない (言語仕様に則ればエラーではないから) が、診断するのは容易だろう。

override文脈キーワードに過ぎないので、まだ識別子として使うことができる:


int override = 7;	// 推奨できない
以下も参照:


オーバーライドの制御: final

時々、プログラマは仮想関数がオーバーライドされるのを禁止したいことがある。 これは final 指定子の追加で実現できるようになった。 例えば:

	struct B {
		virtual void f() const final;	// オーバーライドしないこと
		virtual void g();
	};

	struct D : B {
		void f() const; 	// エラー: D::f が final な B::f をオーバーライドしようとした
		void g();		// OK
	};
オーバーライドを禁止したいという要求にはもっともな理由があるのだが、著者が見てきた final が必要というデモンストレーションのほとんどは、いかに virtual 関数のコストが高いかという間違った仮定に基づいていた。 そういうわけで、もし final 指定子を追加しようとする衝動に駆られたら、どうかその理由が正当なものかダブルチェックして欲しい: 誰かが定義した class が仮想関数を上書きすると意味論的なエラーが発生するのか? final を追加することで、思いもよらないもっと優れた関数の実装の基になったかも知れない class の、未来のユーザの可能性を閉ざしてしまうのだ。 もし開放性の維持を望まないというのなら、なぜ最初にその関数を virtual と定義したのか? この問いに対して、著者が出会ったもっとも説得力のある答えは以下のようなものだ: これはフレームワークの基本的な関数で、フレームワークベンダはオーバーライドする必要があるが、一般的なユーザがオーバーライドするのは安全でない、と。 著者の偏見はこの種の要求に懐疑的なのだが。

性能上の理由 (inline 化) とか、単純に絶対オーバーライドさせたくないだけなら、最初にその関数を virtual と定義しないのがお決まりのより良い答えだ。 C++ は Java じゃないんだから。

finla文脈キーワードに過ぎないので、まだ識別子として使うことができる:


int final = 7;	// 推奨できない

以下も参照:


C99 機能

高度の互換性を維持するため、C 標準化委員会との共同作業で言語に小さな変更をいくつか行った: また、プリプロセスの規約がいくつか追加された: C99 から派生した大量のライブラリ機能 (基本的に C89 から C99 ライブラリへの変更点は全部):

以下も参照:


拡張された整数型

拡張された (精度の) 整数型が存在する場合、その振舞いについての規約がある。

以下を参照。


並列性に伴う動的初期化と破壊

申し訳ないが、この項目を書く時間がない。 以下を参照せよ。


スレッド局所記憶指定子 (thread_local)

申し訳ないが、この項目を書く時間がない。 以下を参照せよ。


unicode 文字

申し訳ないが、この項目を書く時間がない。 また後日確認されたい。


例外のコピーと再送

例外を catch して別のスレッドへ再送するにはどうしたらいいだろう? 標準規格 18.8.5 例外の伝播で説明されているライブラリの魔法をちょこっと使えばよい:


extern template

template の特殊化は、多重インスタンス化を抑止することで、明示的に宣言できるようになる。 例えば:
 
	#include "MyVector.h"

	extern template class MyVector<int>; // 以降で暗黙的にインスタンス化されるのを抑止 --
					// MyVector<int> はどこか別の場所で明示的にインスタンス化

	void foo(MyVector<int>& v)
	{
		// ここで vector を使う
	}
『どこか別の場所』には以下のように書かれているだろう:

	#include "MyVector.h"

	template class MyVector<int>; // MyVector をクライアント (例えば共有ライブラリ) から利用可能にする
これは基本的に、コンパイラとリンカによる大きな重複作業を避けるためのものだ。

以下も参照。


Inline namespace

inline namespace は、バージョニングをサポートする方法を提供することで、ライブラリの進歩を支援することを意図した仕組みだ。 以下を考えよ:

	// ファイル V99.h:
	inline namespace V99 {
		void f(int);	// V98 版よりも巧く何かを行う
		void f(double);	// 新機能
		// ...
	}

	// ファイル V98.h:
	namespace V98 {
		void f(int);	// 何かを行う
		// ...
	}

	// ファイル Mine.h:
	namespace Mine {
	#include "V99.h"
	#include "V98.h"
	}
ここで、namespace Mine には、最新版 (V99) と一つ古い版 (V98) の両方がある。 どちらか特定したいのであれば、以下のようにできる:

	#include "Mine.h"
	using namespace Mine;
	// ...
	V98::f(1);	// 旧版
	V99::f(1);	// 新版
	f(1);		// 既定版
要点は、inline 指定子で、重箱になった namespace からの宣言が、あたかも閉じた namespace の中で宣言したかのようになる、ということだ。

namespace の設計者が書く場所に置かれるため、inline 指定子は、極めて『静的』で、実装者指向の機能であり、全てのユーザに選択を強制する。 Mine のユーザが『V99 でなく V98 を既定にしたい』と言うことはできないのだ。

以下も参照。


明示的な変換演算子

C++98 には暗黙的なコンストラクタと明示的なコンストラクタがあった。 explicit 宣言して定義する明示的なコンストラクタは、他のコンストラクタが暗黙的な変換として使えるところで同じように使えるが、明示的な変換としてしか使えない。 例えば:
	struct S { S(int); };	// 「普通のコンストラクタ」で暗黙の変換を定義
	S s1(1);		// ok
	S s2 = 1;	// ok
	void f(S);
	f(1);		// ok (だが、悪い意味でびっくりすることも -- もし S が vectorだったら?)

	struct E { explicit E(int); };	// 明示的なコンストラクタ
	E e1(1);		// ok
	E e2 = 1;	// エラー (だが、びっくりするかも)
	void f(E);
	f(1);		// エラー (びっくりしないですむ -- int から std::vector へのコンストラクタが explicit なのと同様)

しかしながら、コンストラクタは変換を定義する唯一の仕組みではない。 class を修正できない場合、別の class からの変換演算子を定義することもできる。 例えば:
	struct S { S(int) { } /* ... */ };

	struct SS {
		int m;
		SS(int x) :m(x) { }
		operator S() { return S(m); }	// S には S(SS) がないため; 非侵入的
	};

	SS ss(1);
	S s1 = ss;	// ok; 暗黙的コンストラクタのように振る舞う
	S s2(ss);	// ok; 暗黙的コンストラクタのように振る舞う
	void f(S);
	f(ss);		// ok; 暗黙的コンストラクタのように振る舞う
残念ながら、explicit 変換演算子は存在しない (ごくわずかながら問題のある例があるため)。 C++11 は explicit となるべき変換演算子を許容することに伴う間違いを防ぐことができる。 例えば:
	struct S { S(int) { } };

	struct SS {
		int m;
		SS(int x) :m(x) { }
		explicit operator S() { return S(m); }	// S には S(SS) がないため
	};

	SS ss(1);
	S s1 = ss;	// エラー; 明示的コンストラクタのように振る舞う
	S s2(ss);	// ok ; 明示的コンストラクタのように振る舞う
	void f(S); 
	f(ss);		// エラー; 明示的コンストラクタのように振る舞う

以下も参照:


アルゴリズムの改良

新しいアルゴリズムが単純に追加されたり、新しい言語機能のおかげで実装が改良されたり、新しい言語機能で利用が簡単になったりと、標準ライブラリのアルゴリズムが部分的に改良された: 以下も参照:


コンテナの改良

新しい言語機能と何十年かの価値ある経験によって、標準コンテナに何が起きただろう? まず、もちろん少なくない新顔が加わった: array (固定長コンテナ)、 forward_list (単方向リンクリスト)、 unordered コンテナ (ハッシュテーブル)。 それから、 初期化リスト右辺値リファレンス可変個引数 templateconstexpr のような新機能をが使えるようになった。 std::vector を考えよ。

明らかに、コンテナは標準ライブラリの一部分のみならず、新しい言語機能の御利益を享受している。 以下を考えよ:


スコープ付きアロケータ

コンテナオブジェクトをコンパクトで単純にするために、C++98 は状態を持つアロケータをサポートするコンテナを必須要件としなかった: アロケータオブジェクトがコンテナオブジェクトに格納される必要はない。 これは C++11 でも相変わらず既定のままだが、割付先の領域へのポインタをアロケータに持たせることで、状態を持つアロケータを使うこともできる。 例えば:

	template<class T> class Simple_allocator {	// C++98 形式
		// データなし
		// 普通のアロケータ
	};

	class Arena {
		void* p;
		int s;
	public:
		Arena(void* pp, int ss);
		// p[0..ss-1] から割り付ける
	};

	template<class T> struct My_alloc {
		Arena& a;
		My_alloc(Arena& aa) : a(aa) { }
		// 普通のアロケータ
	};

	Arena my_arena1(new char[100000],100000);
	Arena my_arena2(new char[1000000],1000000);

	vector<int> v0;	// 既定のアロケータを使う割付

	vector<int,My_alloc<int>> v1(My_alloc<int>{my_arena1});	// my_arena1 を使う割付

	vector<int,My_alloc<int>> v2(My_alloc<int>{my_arena2});	// my_arena2 を使う割付

	vector<int,Simple_alloc<int>> v3;	// Simple_alloc を使う割付
概ね、この冗長さは typedef で軽減されるだろう。

既定のアロケータと Simple_alloc が vector オブジェクトの空間を使い切らない保証はないが、エレガントな template メタプログラミングをライブラリの中でちょっと効かせるだけで、保証させることもできる。 従って、アロケータ型の使用が空間的なオーバーヘッドを強いるのは、そのオブジェクトが実際に状態を持つ場合に限られる (My_alloc のように)。

むしろ隠れた問題は、コンテナとユーザ定義アロケータを使う時に起きるだろう: コンテナと同じ割付領域に要素を配置すべきだろうか? 例えば、もしあなたが Your_allocatorYour_string の要素を割り付けるのに使い、私が My_allocatorMy_vector の要素を割り付けるのに使った場合、My_vector<Your_allocator> の string の要素の割付にはどちらのアロケータが使われるだろう? 解決方法は、要素へ渡すアロケータが何か、コンテナに伝えられるようにすることだ。 例えば、アロケータ My_alloc があり、vector<string> に対して My_allocvector の要素と string の要素両方を割り付けたいとしよう。 まず、My_alloc オブジェクトを受け取れる string をつくる必要がある:


	using xstring = basic_string<char, char_traits<char>, My_alloc<char>>;	// 私のアロケータを使う string
次に、この文字列を受け取り、My_alloc オブジェクトを受け取り、文字列へのオブジェクトを渡せる vector をつくらなければならない:

	using svec = vector<xstring,scoped_allocator_adaptor<My_alloc<xstring>>>;	
ここまでやれば、My_alloc<xstring> 型のアロケータをつくることができる:

	svec v(svec::allocator_type(My_alloc<xstring>{my_arena1}));
これで svecMy_alloc を文字列のメモリ割付に使う string の vector になった。 string も My_alloc を使うように指示するのが、標準ライブラリの『アダプタ』 (『ラッパー型』) scoped_allocator_adaptor の新しい点だ。 このアダプタは (自明に) My_alloc<xstring>xstring に必要な My_alloc<char> へ変換できることに注意せよ。

従って、四種類の変種ができる:


	// vector と string は各々の (既定の) アロケータを使う:
	using svec0 = vector<string>;
	svec0 v0;

	// vector (だけ) は My_alloc を使い、string は自身の (既定) アロケータを使う:
	using svec1 = vector<string,My_alloc<string>>;
	svec1 v1(My_alloc<string>{my_arena1});

	// vector と string は My_alloc (上述の通り) を使う:
	using xstring = basic_string<char, char_traits<char>, My_alloc<char>>;
	using svec2 = vector<xstring,scoped_allocator_adaptor<My_alloc<xstring>>>;
	svec2 v2(scoped_allocator_adaptor<My_alloc<xstring>>{my_arena1});

	// vector は My_alloc を使い、string は My_string_alloc を使う:
	using xstring2 = basic_string<char, char_traits<char>, My_string_alloc<char>>;
	using svec3 = vector<xstring2,scoped_allocator_adaptor<My_alloc<xstring>, My_string_alloc<char>>>;
	svec3 v3(scoped_allocator_adaptor<My_alloc<xstring2>, My_string_alloc<char>>{my_arena1,my_string_arena}); 
明らかに、最初の変種 svec0 は、極めて最も一般的だろうが、メモリ関連の制約が厳しいシステムでは、他のバージョン (特に svec2) の方が重要になるかも知れない。 ちょっとした typedef で少しコードが読みやすくなるだろうが、ありがたいことに毎日書くようなものでもない。 scoped_allocator_adaptor2 は、二種類の非既定アロケータ用の scoped_allocator_adaptor の変種である。

以下も参照:


std::array

標準コンテナ array は、固定長のランダムアクセス可能な要素であり、<array> で定義される。 このコンテナは、その要素を保持するのに必要な分以外に空間的なオーバーヘッドがなく、自由記憶を使わず、初期化リストで初期化することができ、その大きさ (要素数) を知ることができ、明示的に指定しない限りポインタに変換されない。 言い換えると、これは組込の配列に殆どそっくりだが、配列の持つ問題には無縁だ。

	array<int,6> a = { 1, 2, 3 };
	a[3]=4;
	int x = a[5];		// x は、既定の要素がゼロ初期化されるため、0 になる
	int* p1 = a;		// エラー: std::array は暗黙的にポインタへ変換されない
	int* p2 = a.data();	// ok: 最初の要素へのポインタ
長さゼロの array も可能だが、初期化リストから array の長さを導出することはできない:

	array<int> a3 = { 1, 2, 3 };	// エラー: 大きさが未知/指定なし
	array<int,0> a0;		// ok: 要素なし
	int* p = a0.data();		// 未既定。試さないこと
標準の array の機能は組込システムプログラミング (や、同じ様に、制限が厳しかったり、性能要件が重要だったり、安全性が重要なタスク) で魅力的なものになる。 これは連続したコンテナなので、普通のメンバ型やメンバ関数の元にできる (ちょうど vector のように):

	template<class C> C::value_type sum(const C& a)
	{
		return accumulate(a.begin(),a.end(),0);
	}

	array<int,10> a10;
	array<double,1000> a1000;
	vector<int> v;
	// ...
	int x1 = sum(a10);
	double x2 = sum(a1000);
	int x3 = sum(v);

また、(潜在的に問題になりがちな) 派生型から基底型への変換はできない:

	struct Apple : Fruit { /* ... */ };
	struct Pear : Fruit { /* ... */ };

	void nasty(array<Fruit*,10>& f)
	{
		f[7] = new Pear();
	};

	array<Apple*,10> apples;
	// ...
	nasty(apples);	// エラー: array<Apple*,10> から array<Fruit*,10> へは変換できない
もしこれが許されたなら、apples の中に Pear を含んでしまいかねない。

以下も参照:


std::forward_list

標準コンテナ forward_list は、<forward_list> で定義されており、基本的には単方向連結リストだ。 これは前方への進行 (だけ) をサポートし、挿入や削除を行っても要素が移動しないことを保証する。 占有する空間は最小限 (空のリストはほとんど一ワードになるだろう) で、size() の操作は提供しない (ので、サイズメンバを持つ必要がない):

	template <ValueType T, Allocator Alloc = allocator<T> >
		requires NothrowDestructible<T>
	class forward_list {
	public:
		// 通常のコンテナ
		// size() なし
		// 逆方向への進行なし
		// back() も push_back() もなし
	};

以下も参照:


ハッシュコンテナ

非順序 (原文: unordered) コンテナはハッシュテーブルの一種だ。 C++11 には四種類の標準コンテナがある: これらは hash_map 等と名付けられるべきだったが、非互換な同じ名前のものが数多く存在するため、委員会は新しい名前を付けざるを得なかった。 思いつく中では unordered_map 等が一番マシな名前だったのだ。 「非順序」は mapunordered_map のキーポイントとなる違いの一つを表している: map 全体を抽出すると、その小なり不等号演算子 (既定では <) による順に並ぶのに対して、unordered_map は小なり不等号演算子がなくても良いし、ハッシュテーブルには自然な順序というものがない。 逆に、map の要素型にはハッシュ関数がなくても良い。

基本的な考え方は、最適化が可能かつもっともらしい場合に、単純に unordered_mapmap の最適化版として使うことだ。 例えば:


	map<string,int> m {
		{"Dijkstra",1972}, {"Scott",1976}, {"Wilkes",1967}, {"Hamming",1968}
	};
	m["Ritchie"] = 1983;
	for(auto x : m) cout << '{' << x.first << ',' << x.second << '}';

	unordered_map<string,int> um {
		{"Dijkstra",1972}, {"Scott",1976}, {"Wilkes",1967}, {"Hamming",1968}
	};
	um["Ritchie"] = 1983;
	for(auto x : um) cout << '{' << x.first << ',' << x.second << '}';
m のイテレータは要素をアルファベット順に表示するが、um はそうならない (偶然並ぶ場合を除いて)。 検索処理は、mum とで全く違う実装になる。 m の場合、検索処理は log2(m.size()) 回の小なり不等号の比較分かかるのに対して、um の場合は一回のハッシュ関数の呼び出しと一回以上の等号比較になる。 要素の数が多くなければ (数十個くらい)、どちらが早いとも言い難い。 もっと要素の数が多くなれば (数千個とか)、unordered_map の検索の方が map より遙かに速くなるかも知れない。

要追記。

以下も参照:


std::tuple

標準ライブラリ tuple (N 個の組) は N 個の値の順列であり、ここで N は 0 以上で、<tuple> で定義される実装定義の最大値以下の定数だ。 tuple とは、無名の構造体であり、そのメンバ型が tuple の要素型であるようなものだと考えて差し支えない。 特に、tuple の要素はコンパクトに格納される; tuple はリンク構造ではないのだ。

tuple の要素型は明示的に指定することも導出する (make_tuple を使って) こともでき、get() を使って添え字 (ゼロ基点) で要素にアクセスできる:


	tuple<string,int> t2("Kylling",123);

	auto t = make_tuple(string("Herring"),10, 1.23);	// t は tuple<string,int,double> 型になる
	string s = get<0>(t);
	int x = get<1>(t);
	double d = get<2>(t);
tuple は、コンパイル時に要素の異種混合リストが必要だが、それを保持する名前付きクラスを定義したくはない時なら、いつでも (直接的にせよ間接的にせよ) 使われる。 例えば、tuplestd::function と std::bind 内部で引数を保持するのに使われている。

もっとも頻繁に使われる tuple は 2-tuple、すなわち pair だ。 しかしながら、pair は std::pair (20.3.3 pair) として標準ライブラリで直接サポートされている。 pairtuple の初期化に使うことはできるが、その逆はできない。

比較演算子 (==, !=, <, <=, >, and >=) は、比較可能な要素型の tuple では定義される。

以下も参照:


メタプログラミングと type traits

申し訳ないが、また後日確認されたい。


std::function と std::bind

標準関数オブジェクト bindfunction は、<functional> で (他のたくさんの関数オブジェクトと共に) 定義されている。 これらは関数と関数の引数を扱うための物だ。 bind は関数 (または関数オブジェクト、あるいは () 構文で呼び出せる物なら何でも) を受け取り、その関数の一つ以上の引数を『束縛』または転位させた関数オブジェクトを作り出す。 例えば:

	int f(int,char,double);
	auto ff = bind(f,_1,'c',1.2);	// 戻り値型の導出
	int x = ff(7);			// f(7,'c',1.2);
この引数の束縛は、普通『カリー化 (原文: Currying)』と呼ばれる。 _1 は、fff 経由で呼び出されたときに、ff の第一引数を渡すことを指示するプレースホルダオブジェクトだ。 第一引数は _1、第二引数は _2、等となる。 例えば:

	int f(int,char,double);
	auto frev = bind(f,_3,_2,_1);	// 引数の順を逆にする
	int x = frev(1.2,'c',7);	// f(7,'c',1.2);
auto のおかげで bind の結果の型を指定しなくてすんでいることに注意。

オーバーロードされた関数では、どの関数を束縛するか明示する必要があるため、引数を単純に束縛することはできない:


	int g(int);
	double g(double);	// g() はオーバーロードされている

	auto g1 = bind(g,_1);				// エラー: どの g()?
	auto g2 = bind((double(*)(double))g,_1);	// ok (だが醜い)

bind() には二つの変種がある: 一つ目の変種は上述したものだが、戻り値型を明示的に指定する「古い」バージョンだ。

	auto f2 = bind<int>(f,7,'c',_1);	// 明示的な戻り値型
	int x = f2(1.2);			// f(7,'c',1.2);
二つ目のバージョンは、一つ目の (ユーザにとってもっとも単純な) バージョンが C++98 では実装できなかったために必要だったもので、広く使われている。

function は、(...) 構文で呼び出せるものなら何でも値として保持できる型だ。 特に、bind の結果を function に代入できる。 function の使い方は非常に単純だ。 例えば:


	function<float (int x, int y)> f;	// 関数オブジェクトを作成

	struct int_div {			// () で呼び出せる何か
		float operator()(int x, int y) const { return ((float)x)/y; };
	};

	f = int_div();				// 代入
	cout << f(5, 3) << endl;		// 関数オブジェクト経由で呼び出し
	std::accumulate(b,e,1,f);		// 美しい渡し方
メンバ関数は余分な引数を持つ自由関数として扱うことができる。

	struct X {
		int foo(int);
	};

	function<int (X*, int)> f;
	f = &X::foo;		// メンバへのポインタ

	X x;
	int v = f(&x, 5);	// x の X::foo() を引数 5 で呼び出し
	function<int (int)> ff = std::bind(f,&x,_1);	// f の最初の引数は &x
	v=ff(5); 		// x.foo(5) の呼び出し
function はコールバックや引数として操作を受け渡したりするのに便利だ。 C++98 の標準ライブラリ関数オブジェクト mem_fun_tpointer_to_unary_function 等の代わりにも使えるだろう。 同様に、bind()bind1()bind2() の代わりになるだろう。

以下も参照:


unique_ptr

unique_ptr は核心部分で 右辺値リファレンスと移動セマンティクスに依存している。

次に挙げるのは例外安全でないコードの伝統的な断片だ:


	X* f()
	{
		X* p = new X;
		// 何かをする - そして例外が発生するかも知れない
		return p;
	}
自由記憶上のオブジェクトへのポインタを unique_ptr に持つのが解決法だ:

	X* f()
	{
		unique_ptr<X> p(new X);		// {new X} としても良いが、= new X はダメ
		// 何かをする - そして例外が発生するかも知れない
		return p.release();
	}
これで、もし例外が発生しても、unique_ptr が (暗黙的に) 指しているオブジェクトを削除してくれる。 これは基本的な RAII だ。 しかしながら、本当に組込のポインタを返す必要がない限り、unique_ptr のまま返した方がいいだろう:

	unique_ptr<X> f()
	{
		unique_ptr<X> p(new X);		// {new X} としても良いが、= new X はダメ
		// 何かをする - そして例外が発生するかも知れない
		return p;	// 所有権が f() の外へ渡る
	}
f は以下のように使う:

	void g()
	{
		unique_ptr<X> q = f();	// 移動コンストラクタを使う移動
		q->memfct(2);			// q を使う
		X x = *q;			// 指している先のオブジェクトをコピー
		// ...
	}	// q と q が指すオブジェクトは、抜けるときに破棄される
unique_ptr には『移動セマンティクス』があるため、f() の呼出結果の右辺値による q の初期化では、単純に q へ所有権が移るだけだ。

unique_ptr の使い道の一つに、コンテナへのポインタの格納がある。 これは、組込のポインタと同様だが、例外安全性に関する問題はない (更に、ポインタが指す要素の破棄の保証もできる):


	vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} };

unique_ptr は単純な組込のポインタで表現されており、組込のポインタに対するオーバーヘッドは無視できる程度だ。 特に、unique_ptr はいかなる形の動的チェックも提供しない。

以下も参照


shared_ptr

shared_ptr は、所有権が共有されていることを表現するために使われる; 所有権の共有とは、二つのコードの切れ端が何らかのデータにアクセスする必要があるが、どちらも排他的な所有権 (オブジェクトを破棄する責任という観点で) を持たないということだ。 shared_ptr は、参照カウントがゼロになった時に参照先のオブジェクトを破棄する、一種のカウンタ付きポインタだ。 以下にかなりわざとらしい例を挙げる:
	void test()
	{
		shared_ptr<int> p1(new int);	// カウンタは 1
		{
			shared_ptr<int> p2(p1);	// カウンタは 2
			{
				shared_ptr<int> p3(p1);	// カウンタは 3
			}	// 参照カウントが 2 に戻る
		} // 参照カウントが 1 に戻る
	}	// ここで参照回数が 0 になり、int が削除される。

もっと現実的な例は、一般的なグラフにおいて、ノードへのポインタを破棄する際に、そのノードを指すポインタが他にあるか分からないような場合の、ノードを指すポインタだろう。 ノードがデストラクタの動作を必要とするリソース (例えば、ノードが破棄される時に閉じる必要があるファイルなら、ファイルハンドル) を保持しているかもしれない場合だ。 shared_ptrガベージコレクタプラグインのようなものだと考えても良いが、それは十分に経済的なくらいガベージが少ないか、その実行環境でガベージコレクタが使えないか、あるいは、管理するリソースがメモリだけでない (例えばファイルハンドル) 場合に限られる。 例えば:
	struct Node {	// メモ: ノードは複数の他のノードから参照されうる。
		shared_ptr<Node> left;
		shared_ptr<Node> right;
		File_handle f;
		// ...
	};
ここで Node のデストラクタ (暗黙的に生成されるデストラクタでよい) はそのサブノードを破棄する。 すなわち、leftright のデストラクタが呼び出される。 leftshared_ptr なので、left が最後のポインタであれば、その先の Node (何であろうと) が破棄される。 right も同様に扱われ、f のデストラクタはたとえ f を必要とするものがあっても呼び出される。

単に所有権を左から右へ移すだけなら、shared_ptr を使うべきでないことに注意されたい; そのために unique_ptr があるのであって、unique_ptr の方がより安価で優れている。 ファクトリ関数やその類から値を戻すためにカウンタ付きポインタを使っているのなら、shared_ptr よりも unique_ptr へのアップグレードを考えた方がよい。

メモリリークを防ごうとして何の考えもなしにポインタを shared_ptr で置き換えるのはやめて欲しい; shared_ptr は万能薬ではないし、代償が伴うのだ:

shared_ptr所有権の共有を表現するものだが、所有権を共有することは著者の理想ではない: オブジェクトの所有権が明確で、明確に予測可能な寿命があるなら、その方が良いのだ。

以下も参照


weak_ptr

weak_ptr は、shared_ptr を使ったデータ構造のループを避けるために必要なものとして説明されることが多い。 著者は weak_ptr を、
  1. それが存在する時 (だけ) アクセスする必要があり、
  2. (存在する時以外は) 破棄されたことが分かり、
  3. 最後の使用 (通常は匿名メモリリソースの破棄) の後で呼び出されるデストラクタを持つ必要がある
ポインタだと考えた方が良いと思っている。 昔の『アステロイドゲーム』の実装を考えて欲しい。 全ての隕石は『ゲーム』が保持しているが、それぞれの隕石は周りの隕石の動きを把握し、衝突を扱う必要がある。 通常、衝突に伴って一つ以上の隕石が破壊される。 各隕石は周りにある他の隕石のリストを持つ必要がある。 このリストは『生きている』隕石を保持すべきでない (ので shared_ptr は不適切である) ことに注意して欲しい。 他方で、隕石は、他の隕石が (衝突結果を計算するため等で) 参照している間は破壊されてはならない。 加えて、明らかに、隕石のデストラクタはリソース (グラフィックシステムへの接続等) を解放するために呼び出されなくてはならない。 必要なものは、まだ無傷かもしれない隕石のリストと、「もし存在するのなら、それを保持しておく」方法だ。 weak_ptr がまさにこのためのものだ:
	void owner()
	{
		// ...
		vector<shared_ptr<Asteroid>> va(100);
		for (int i=0; i<va.size(); ++i) {
			// ... 新しい隕石用に周りの隕石との計算を行う ...
			va[i].reset(new Asteroid(weak_ptr<Asteroid>(va[neighbor]));
			launch(i);
		}
		// ...
	}
reset() は新しいオブジェクトを参照する shared_ptr を作りだす関数だ。

見ての通り、『owner』は、各々の新しい Asteroid を単なる neighbor の一つとして与えるだけに、極度に単純化された。 カギは、隕石の weak_ptr を neighbor へ渡したことだ。 owner は、Asteroid がいつ参照されようと (ただし、それ以外では真でない) 共有所有権を表す shared_ptr を保持し続ける。 Asteroid の衝突計算は以下のようになるだろう:

	void collision(weak_ptr<Asteroid> p)
	{
		if (auto q = p.lock()) {	// p.lock は p のオブジェクトへの shared_ptr を返す
			// ... この隕石はまだ存在する: 計算...
		}
		else {
			// ... おおっと: この隕石はすでに破壊されている: これは放っておいて良い (これを指す weak_ptr の破棄...)
		}
	}
もし owner がゲームを終了して全ての Asteroid を delete することになった (所有権を表す shared_ptr を破棄することで) としても、衝突計算中の Asteroid は全て正しく終了することに注意すること (なぜなら p.lock() の後で、無効にならない shared_ptr があるから)。

著者は、weak_ptr の利用が、『生の』shared_ptr の利用頻度よりはるかに少なくなると予想しており、unique_ptrshared_ptr の利用頻度よりもはるかに多くなって欲しいと考えている。 unique_ptr はより単純な (そしてより効率的な) 所有権の書き表し方であり (ゆえに) より良い局所性を意味することになるからだ。

以下も参照


ガベージコレクション ABI

ガベージコレクション (参照されていないメモリ領域の自動回収) は C++ ではオプションだ。 つまり、ガベージコレクションは実装の必須要件ではない。 しかしながら、C++11 では GC を使った場合にできることと ABI (アプリケーションバイナリインターフェース) を、動作をコントロールする際の一助にするため、定義している。

ポインタと寿命に関するルールは「安全に導き出されたポインタ」(3.7.4.3) の節で説明されているが、これを大まかにいうと「new で割り付けられた何かかそのサブオブジェクトを指すポインタ」のことだ。 ここで「安全に導き出されていないポインタ」、あるいは「特徴的な (disguised) ポインタ」と呼ばれたりする、あなたが良い振る舞いで一般人にわかりやすいと考えることを望むプログラムの中ではやらないようなもの、の例をいくつか挙げる:

ポインタを変装させる正当な理由はある (例外的にメモリ制約のあるアプリケーションでの xor トリック等) が、一部のプログラマが考えるほど多くはない。

プログラマは、(例えば想像等で) 発見可能なポインタがない場所や、コレクタがメモリを指すポインタを発見できない場合でも再利用してはならないものを、指定することができる:


	void declare_reachable(void* p);	// p で始まるメモリ領域
						// (と、その大きさを知っている何らかの
						// アロケータ操作で割り付けられた領域)
						// は回収してはならない
	template<class T> T* undeclare_reachable(T* p);

	void declare_no_pointers(char* p, size_t n);		// p[0..n] にはポインタなし
	void undeclare_no_pointers(char* p, size_t n);
プログラマはポインタ安全性と回収についての規則が有効か調べることもできる:

	enum class pointer_safety {relaxed, preferred, strict };
	pointer_safety get_pointer_safety();
もし、安全に導き出されていないポインタの値で参照を行ったり割り付けを破棄したりして、そのポインタが参照している完全なオブジェクトが動的記憶期間の範囲内にあり、それが前もって到達可能 (20.7.13.7) と宣言されていない場合、その動作は未定義だ。 他のお望みの選択肢を指定する標準的な方法はない。 それは『実装品質』とか『プログラミング環境』の問題だと考えられる。

以下も参照


メモリモデル

メモリモデルは、殆どのプログラマが現代的なコンピュータハードウェアの詳細を考える必要などまずあり得ないと、マシンアーキテクト屋とコンパイラ屋が合意したことによるものだ。 メモリモデルなしでは、スレッド、ロック、ロックなしプログラミングに関する殆どが意味をなさないだろう。

カギとなる保証: 二つの実行スレッドは、異なるメモリの位置を、互いに干渉することなく更新したり参照したりできる。 だが、『異なるメモリの位置』とは何なのか? メモリの位置とは、スカラー型のオブジェクト、ないしはゼロより大きい幅を持つ全ての整列したビットフィールドの最大列のどちらかだ。 例えば、以下の S は正確に四つに別れたメモリの位置を持つ:


	struct S {
		char a;			// 位置 #1
		int b:5,		// 位置 #2
		int c:11,
		int :0,			// メモ: :0 は「特別な」位置
		int d:8;			// 位置 #3
		struct {int ee:8;} e;	// 位置 #4
	};
なぜこれが重要なのか? これは自明ではないのか? これが常に真でないことなどあり得るのか? 問題は、複数の演算が実際に動作する際に、複数の (明らかに) 無関係な命令同士が同時に動いてしまい、メモリハードウェアの気まぐれが表面化し得るということなのだ。 実際、コンパイラの支援がなければ、命令とデータパイプラインと細かいキャッシュ使用の問題が、完全に制御不能な形でアプリケーションプログラマに襲いかかるだろう。 二つのスレッドが共有データを持つと定義されていない場合ですら、そうなるのだ! 二つの別々にコンパイルされた『スレッド』を考えよ:

	// スレッド1:
	char c;
	c = 1;
	int x = c;

	// スレッド2:
	char b;
	b = 1;
	int y = b;
より現実的な議論をするために、コンパイラ/オプティマイザがメモリアクセスを切り詰めて cb を単純に無視し、xy を直接 1 で初期化することはない、と保証するため、別々に (各スレッドの範囲で) コンパイルされたものとする。 xy の取り得る値は何になるだろう? C++11 に従えば、正しい答えは明白に一つだ: 1 と 1。 これが面白い理由は、従来の非並列な正しい C や C++ コンパイラでは、取り得る値が 0 と 0 (ありそうにないが)、1 と 0、0 と 1、1 と 1 のどれにもなり得ることだ。 これは『でたらめ』に見える。 どうしてか? リンカは cb をそれぞれ隣接して (同じワードに) 配置するかも知れない -- C や C++ の 1990 年代の標準では何とも唱っていない。 これは即ち、C++ は、本物の並列ハードウェアのことを考慮して設計されていない全ての言語と同様、ということだ。 しかしながら、殆どの現代的なプロセッサは単一の文字だけを読み書きできず、ワード全体を読み書きする必要があるため、c への代入が、実際には、『c を含むワードを読み、c の部分を置き換え、ワードを書き直す』という動作になる。 b への代入も同様なので、二つのスレッドが (ソーステキスト上では) データを共有していなかったとしても、上書きしてしまう機会は大いにあるのだ!

そこで、C++11 では『別れたメモリの位置』の問題が発生しないように保証した。 より正確には: メモリの位置は、両方共リードアクセスされる限り、何らかのロックなしには二つのスレッドから安全にアクセスすることはできないということだ。 単一ワード中の異なるビットフィールドは別れたメモリ位置ではないので、何らかの形のロックなしにビットフィールドを持つ構造体をスレッド間で共有しないこと。 注意書きを別にすれば、C++ メモリモデルは、単純に『みんなが思っている通り』ということだ。

しかしながら、低水準の並列性問題については常に簡単に安直な考えができるわけではない。 以下を考えよ:


	// x==0 かつ y==0 で始まる

	if (x) y = 1;	// スレッド 1 

	if (y) x = 1;	// スレッド 2 

これに何か問題があるだろうか? より正確に言うと、データ競合があるだろうか? (答えはない)

ありがたいことに、我々は既に現代に適応済で、全ての並列 C++ コンパイラ (筆者の知る範囲で) は唯一の正しい答えを何年も前から提供している。 ほとんどの (残念ながらまだ全てではないが) トリッキーな質問に対しても同様だ。 結局のところ、C++ は『ずっと』並列システムの重要なシステムプログラミングに使われてきたのだ。 この標準でずっとより良くなるだろう。

以下も参照


スレッド

スレッドはプログラムの実行/演算の表現だ。 C++11 では、殆どの現代的なコンピューティングがそうであるように、スレッドが他のスレッドとアドレス空間を共有することができる -- そして普通は共有する。 この点で、一般的に他のプロセスと直接データを共有しないプロセスとは異なっている。 C++ は、これまで様々なハードウェアとオペレーティングシステムで、スレッド実装の主役であり続けてきたが、新しくなったことは、標準ライブラリのスレッドライブラリ、標準スレッド ABI だ。

平行性、並列性、スレッドについては、多くの分厚い本と何万もの論文が書かれているので、この FAQ の項目では単に大筋をなぞるに留める。 並列性についてきちんと考えるのは大変なのだ。 並列プログラミングについて理解を深めたいなら、最低限本を一冊読んで欲しい。 マニュアルや標準、FAQ だけに頼ってはいけない。

スレッドは std::thread を関数や関数オブジェクト (ラムダを含む) で構築することにより起動される:

	
	#include<thread>

	void f();

	struct F {
		void operator()();
	};

	int main()
	{
		std::thread t1{f};	// f() は別のスレッドで実行
		std::thread t2{F()};	// F()() は別のスレッドで実行
	}
残念ながら、これはあまりまともな結果にならない -- f()F() が何をしようが。 この思わぬ障害は、t1f() を実行する前か後、あるいは t2F() を実行する前か後に、このプログラムが終了するかも知れないことだ。 二つのタスクが完了するのを待ち合わせる必要があるのだ:

	int main()
	{
		std::thread t1{f};	// f() は別のスレッドで実行
		std::thread t2{F()};	// F()() は別のスレッドで実行

		t1.join();	// t1 を待つ
		t2.join();	// t2 を待つ
	}
join() で、スレッドが完了するまで停止しないことを保証する。 『join』は『スレッドが停止するまで待つ』ことを意味する。

実行すべきタスクに引数をいくつか渡したい (スレッドが実行する何かのタスクを呼び出す) こともある。 例えば:


	void f(vector<double>&);

	struct F {
		vector<double>& v;
		F(vector<double>& vv) :v{vv} { }
		void operator()();
	};

	int main()
	{
		std::thread t1{std::bind(f,some_vec)};	// f(some_vec) は別のスレッドで実行
		std::thread t2{F(some_vec)};		// F(some_vec)() は別のスレッドで実行

		t1.join();
		t2.join();
	}
基本的には、標準ライブラリ bind で引数付きの関数オブジェクトを作る。

一般的には、実行したタスクから戻ってきた結果を受け取りこともあるだろう。 素のタスクには戻り値の表記がないので、そのような用途には std::future をお勧めする。 あるいは、タスクへ結果を戻す引数を渡してそこへ格納するよう指示しても良い: 例えば:


	void f(vector<double>&, double* res);	// res に結果を格納

	struct F {
		vector<double>& v;
		double* res;
		F(vector<double>& vv, double* p) :v{vv}, res{p} { }
		void operator()();	// res に結果を格納
	};

	int main()
	{
		double res1;
		double res2;

		std::thread t1{std::bind(f,some_vec,&res1)};	// f(some_vec,&res1) は別スレッドで実行
		std::thread t2{F(some_vec,&res2)};		// F(some_vec,&res2)() は別スレッドで実行

		t1.join();
		t2.join();
		
		std::cout << res1 << ' ' << res2 << '\n';
	}
だが、エラーはどうなるのだろう? もしタスクが例外を投げたらどうなるのか? タスクが例外を投げ、それを自分自身で捕捉しない場合、std::terminate() が呼び出される。 これは、一般的にはプログラムが終了することを意味する。 普通は何とかしてこれを避けたい。 std::future なら例外を親/呼出元スレッドに送出できる; 著者が future を好む理由の一つだ。 さもなくば、何らかの種類のエラーコードを返却すること。

thread がスコープから抜けた時は、そのタスクが完了していない限り、プログラムは terminate() する。 これは明らかに避けるべきだ。

thread に対して停止するよう要求 (可能な限り速やか、かつ段階を追って終了するよう要求するとか) したり、スレッドを強制停止させる (kill のような) 方法はない。 以下はオプションとなっている。

これが委員会で合意できたことの全てだ。 特に、POSIX の代表は、C++ のリソースモデルがデストラクタに依っているにも関わらず、いかなる形の『スレッドのキャンセル』にも強硬に反対した。 全てのシステムと全てのあり得るアプリケーションにとっての完全な解など存在しないのだ。

スレッドの基本的な問題はデータの競合だ; 単一のアドレス空間で実行中の二つのスレッドが独立してあるオブジェクトにアクセスできることで、未定義の結果が発生してしまうからだ。 片方 (あるいは両方とも) のスレッドがオブジェクトに書き込み、もう片方 (あるいは両方とも) がそのオブジェクトを読み出すと、その操作は『競合』することになる。 その結果は単なる未定義でなく、普通は完全に予測不能になるのだ。 そこで C++11 ではプログラマがデータ競合を回避できるよう、いくつかの規則/保証を提供している:

複数のスレッドによる、ストリームオブジェクト、ストリームバッファオブジェクト、C ライブラリのストリームへの並列アクセスは、特に別記のない限り、データ競合を引き起こす。 従って、何らかのアクセス制御をかけない限り、二つのスレッド間で出力ストリームを共有してはならない。

以下は可能だ。

以下も参照


相互排他

mutex はマルチスレッドシステムでのアクセス制御に用いられるプリミティブオブジェクトだ。 最も基本的な使い方としては

	std::mutex m;
	int sh;	// 共有データ
	// ...
	m.lock();
	// 共有データの操作:
	sh+=1;
	m.unlock();
ただ一つのスレッドだけが、lock()unlock() の間のコード (しばしばクリティカルリージョンと呼ばれる) を実行できる。 一つ目のスレッドがクリティカルリージョンを実行している時に、二つ目のスレッドが m.lock() しようとした場合、一つ目のスレッドが m.unlock() を実行するまで二つ目のスレッドはブロックされる。 これは単純だ。 単純でないのは、深刻な問題を引き起こさないように mutex を使う方法だ: スレッドが unlock() するのを『忘れた』ら? スレッドが同じ mutex を lock() しようとしたら? スレッドが unlock() するまでに非常に長い時間が掛かったら? スレッドが仕事をこなすのに二つの mutex を lock() する必要があったら? 完全な答えには本が何冊もいる。 ここでは (セクションのロックによる) 本当に簡単な内容に留める。

lock() に加えて、mutex には、ブロックされることなくクリティカルリージョンに進入可能か試行する try_lock() 操作がある:


	std::mutex m;
	int sh;	// 共有データ
	// ...
	if (m.try_lock()) {
		// 共有データの操作:
		sh+=1;
		m.unlock();
	else {
		// 多分他のことをする
	}

recursive_mutex は、スレッドが複数回取得してよい mutex だ:


	std::recursive_mutex m;
	int sh;	// 共有データ
	// ...
	void f(int i)
	{
		// ...
		m.lock();
		// 共有データの操作:
		sh+=1;
		if (--i>0) f(i);
		m.unlock();
		// ...
	}
ここでは f() 自身を乱暴に呼び出している。 通常、このコードは更に油断ならない。 f() を呼び出す行が、g() を呼び出し、それが h() を呼び出し、それが f() を呼び出す間接的な再起呼出になっているかも知れない。

mutex を続く十秒間確保する必要がある場合は? timed_mutex クラスがその役割を提供する。 これは try_lock() にタイムアウト制限が付いた特殊化版だ:


	std::timed_mutex m;
	int sh;	// 共有データ
	// ...
	if (m.try_lock_for(std::chrono::seconds(10))) {
		// 共有データの操作:
		sh+=1;
		m.unlock();
	}
	else {
		// mutex を確保していないので、何か他のことをする
	}
try_lock_for() は引数として duration を受け取り、その相対時間の間、待機する。 ある決まった時刻 time_point まで待機したい場合は、try_lock_until() を使えばよい:

	std::timed_mutex m;
	int sh;	// 共有データ
	// ...
	if (m.try_lock_until(midnight)) {
		// 共有データの操作:
		sh+=1;
		m.unlock();
	}
	else {
		// mutex を確保していないので、何か他のことをする
	}
midnight は出来の悪いジョークだ: mutex のような低水準の機構では、時間分解能は時間単位ではなくミリ秒単位になるだろう。

もちろん、recursive_timed_mutex もある。

mutex はリソース (実際のリソースを表すのに用いられるリソースと大体同じように) と考えられ、それが役に立つためには少なくとも二つのスレッドから見えなければならない。 従って、mutex をコピーしたり移動することはできない (ハードウェアの入力レジスタをコピーを作れないのと同じように)。

lock()unlock() を合致させるのは驚くほど難しくなることもある。 複雑な制御構造や、エラーや、例外のことを考えてみて欲しい。 選択の余地があるのなら、mutex の操作に lock を使うこと; あなたは救われ、ユーザは長い待ちから救われるだろう。

以下も参照。


lock

lock は、mutex への参照を保持することができ、lock の破棄時 (ブロックスコープを抜ける時のように) に mutexunlock() するオブジェクトだ。 threadlock を用いることで、mutex の所有権に関するごたごたを例外安全な振る舞いにする助けになる。 言い換えれば、lock は相互排他に関する リソース確保は初期化 (RAII) の実装だ。 例えば:

	std::mutex m;
	int sh;	// 共有データ
	// ...
	void f()
	{
		// ...
		std::unique_lock lck(m);
		// 共有データの操作:
		sh+=1;
	}
lock を移動させることはできる (lock の目的は非局所リソースを局所的に表わすことだ) が、コピーはできない (どのコピーがリソース/mutex を所有するというのか?)。

この安直な lock の図式は、mutex にできることが全て可能で、より安全な unique_lock により雲行きが怪しくなる。 例えば、ロックの試行に lock を使える:


	std::mutex m;
	int sh;	// 共有データ
	// ...
	void f()
	{
		// ...
		std::unique_locklck(m,std::defer_lock);	// lock を作るが、mutex は確保しない
		// ...
		if (lck.try_lock()) {
			// 共有データの操作:
			sh+=1;
		}
		else {
			// 何か他のことをする
		}
	}
同様に、unique_locktry_lock_for() や try_lock_until をサポートする。 lock を使わずに mutex を直接使うことで、例外の扱いや unlock() 忘れをせずにすむ。 並列プログラミングでは、得られる限りのあらゆる支援が必要なのだ。

二つのリソースを表すのに二つの mutex が必要な場合は? 安直な方法は順に mutex を取得することだ:


	std::mutex m1;
	std::mutex m2;
	int sh1;	// 共有データ
	int sh2
	// ...
	void f()
	{
		// ...
		std::unique_lock lck1(m1);
		std::unique_lock lck2(m2);
		// 共有データの操作:
		sh1+=sh2;
	}
このコードでは、何か他のスレッドが m1m2 の逆順の取得を試行できるため、先行する片方の lock の後、二つ目を永遠に待ち続けるという、潜在的に死んだフローがある (これをデッドロックと呼ぶ)。 システム中に多くのロックがある場合、これは本当に危険だ。 そこで、標準 lock は (安全に) 二つ以上の lock の取得の試行のため、二つの関数を提供している:

	void f()
	{
		// ...
		std::unique_lock lck1(m1,std::defer_lock);	// lock を作るが、mutex の獲得はまだ試行しない
		std::unique_lock lck2(m2,std::defer_lock);
		std::unique_lock lck3(m3,std::defer_lock);
		lock(lck1,lck2,lck3);
		// 共有データの操作
	}
明らかなことだが、lock() の実装にはデッドロックを避けるために細心の注意をもって当たる必要がある。 本質的に、これは try_lock() を注意深く使うのと同じことだ。 lock() が全てのロックを獲得できなかった場合、例外が送出される。 実際には、lock()lock()try_lock()unlock() メンバ関数と何でも引数を取れるため (mutex のように)、どの例外を lock() が送出するか規定することができなかった。 引数に依存するからだ。

try_lock() の方を使用したいなら、lock() と同じものがあることが参考になる。


	void f()
	{
		// ...
		std::unique_lock lck1(m1,std::defer_lock);	// lock を作るが、mutex の獲得はまだ試行しない
		std::unique_lock lck2(m2,std::defer_lock);
		std::unique_lock lck3(m3,std::defer_lock);
		int x;
		if ((x = try_lock(lck1,lck2,lck3))==-1) {	// C の世界にようこそ
			// 共有データの操作
		}
		else {
			// x は取得できなかった mutex のインデックスを持つ
			// 例えば、lck2.try_lock() が失敗した場合は x==1
		}
	}

以下も参照。


条件変数

条件変数は、他の条件待ちをしているスレッドから通知が来るか、システム時刻が到来するまで、スレッドをブロックするのに使われる同期基本命令を提供する。

申し訳ないが、この項目を書く時間がない。 また後日確認されたい。

以下も参照


時間ユーティリティ

ある時刻やタイミングに応じて何かをやらせたいというのはよくあることだ。 例えば、標準ライブラリの mutexlock では、thread を一定期間 (duration) 待機させたり、ある時刻 (time_point) まで待機させるオプションを提供している。

現在の time_point を知りたい場合、now() を三つのうち一つから呼び出すことができる: system_clockmonotonic_clockhigh_resolution_clock だ。 例えば:


	monotonic_clock::time_point t = monotonic_clock::now();
	// 何かする
	monotonic_clock::duration d = monotonic_clock::now() - t;
	// 何かするのに d 時間単位かかった
clocktime_point を返す。 duration は同じ clock から見た二つの time_point の差だ。 例によって、細かいことに拘らないなら、auto が友人になる。

	auto t = monotonic_clock::now();
	// 何かする
	auto d = monotonic_clock::now() - t;
	// 何かするのに d 時間単位かかった

この時間機能はシステムの深淵な利用を効果的にサポートすることを意図したもので、スケジュール帳をメンテナンスするのに便利な機能を提供するわけではないのだ。 実際、時間機能は高エネルギー物理の切迫したニーズに由来する。 全ての時間スケール (世紀とかピコ秒とか) を表現できるようにしたり、単位や誤記、丸め誤差に関する混乱を避けるため、durationtime_point はコンパイル時有理数パッケージを用いて表現される。 duration には二つの部分がある: クロック数『tick』と tick が何を意味するか (秒とかミリ秒とか) を表すもの (『period』) で、period の部分は durations 型になっている。 この表は、標準ヘッダ <ratio> からのもので、SI 単位系 (MKS 単位系やメートル法としても知られる) の時間を定義したものだが、利用のスコープに関する考えが分かるだろう:


	// SI 単位系コンビニエンス typedef:
	typedef ratio<1, 1000000000000000000000000> yocto;	// 条件付サポート
	typedef ratio<1,    1000000000000000000000> zepto;	// 条件付サポート
	typedef ratio<1,       1000000000000000000> atto;
	typedef ratio<1,          1000000000000000> femto;
	typedef ratio<1,             1000000000000> pico;
	typedef ratio<1,                1000000000> nano;
	typedef ratio<1,                   1000000> micro;
	typedef ratio<1,                      1000> milli;
	typedef ratio<1,                       100> centi;
	typedef ratio<1,                        10> deci;
	typedef ratio<                       10, 1> deca;
	typedef ratio<                      100, 1> hecto;
	typedef ratio<                     1000, 1> kilo;
	typedef ratio<                  1000000, 1> mega;	
	typedef ratio<               1000000000, 1> giga;
	typedef ratio<            1000000000000, 1> tera;
	typedef ratio<         1000000000000000, 1> peta;
	typedef ratio<      1000000000000000000, 1> exa;	
	typedef ratio<   1000000000000000000000, 1> zetta;	// 条件付サポート
	typedef ratio<1000000000000000000000000, 1> yotta;	// 条件付サポート
コンパイル時有理数は、有効な durationtime_point の全ての組み合わせについて、通常の四則演算子 (+-*/) と比較演算子 (==、!=、<、<=、>、>=) を提供する (例えば、time_point 同士を加算することはできない)。 これらの演算子はオーバーフローやゼロ除算のチェックも行う。 これはコンパイル時の機能なので、実行時の性能を気にする必要はない。 加えて、duration については ++、--、+=、-=、*=、/= を使用できるし、time_point tpduration d については tp+=dtp-=d とできる。

ここで、<chrono> で定義されている、標準の duration 型を使った値の例をいくつか挙げる:


	microseconds mms = 12345;
	milliseconds ms = 123;
	seconds s = 10;
	minutes m = 30;
	hours h = 34;

	auto x = std::chrono::hours(3);			// namespace を明示
	auto x = hours(2)+minutes(35)+seconds(9);	// 適当な「using」があると仮定
duration を小数で初期化することはできない。 例えば、2.5 秒ではなく、2500 ミリ秒を使うこと。 これは、duration を『tick』の数値に読み替えているためだ。 各々の tick は duration の『period』単位 (上述した millikilo のような) で表される。 既定の単位は seconds なので、period が 1 で tick が 1 の duration は一秒に当たる。 duration を明示的に表現することもできる:

	duration<long> d0 = 5;			// 秒 (既定)
	duration<long,kilo> d1 = 99;		// キロ秒!
	duration<long,ratio<1000,1>> d2 = 100;	// d1 と d2 は同じ型 ("kilo"は"1000 倍"を意味する)
実際に duration で、例えば出力のようなことを行う場合は、 とか マイクロ秒 といった単位を与えてやる必要がある。 例えば:

	auto t = monotonic_clock::now();
	// 何かする
	nanoseconds d = monotonic_clock::now() - t;	// 計算結果はナノ秒で欲しい
	cout << "何かするのに " << d << " ナノ秒かかった\n";
あるいは、duration を浮動小数に変換して (誤差を丸めて) もよい。

	auto t = monotonic_clock::now();
	// 何かする
	auto d = monotonic_clock::now() - t;
	cout << "何かするのに " << duration_cast<double>(d).count() << " 秒かかった\n";
count() は『tick』の数だ。

以下も参照


原子性

申し訳ないが、この項目を書く時間がない。 また後日確認されたい。

以下も参照


std::future と std::promise

並列プログラミングは、特に threadlock で気の利いたことをしようとすると、難しくなりがちだ。 条件変数原子性操作を (ロックなしプログラミングで) 使う場合はなおさら難しい。 C++11 は、別のスレッドの子タスクから値を返したり、packaged_task にタスクを起動させるために、futurepromise を提供している。 futurepromise に関して重要な点は、明示的なロックを使用することなく、二つのタスク間で効率的に値を受け渡せるということだ。 基本的な考え方は単純だ: タスクが起動元のスレッドへ値を返したい時は、その値を promise に設定する。 実装は、promise に繋がっている future から取り出される値を何とかして作る。 これで、呼出元 (大抵ははタスクの起動元) はその値を読むことができる。 更に単純にするためには、async() を参照すること。

標準には三種類の future があって、future がもっとも単純な用途向け、shared_futureatomic_future はいくらかトリッキーな用途のためのものだ。 future がもっとも単純で、著者に必要なことが全て可能であるため、ここでは future を示すに留める。 future<X>f を呼び出している場合、そこから X 型の値を get() することができる:


	X v = f.get();	// 必要なら得られる値が算出されるまで待機
値がまだ存在しない場合、到着するまでこのスレッドはブロックされる。 値が算出できなかった場合、get() は例外を送出するかも知れない (システムまたは値を get() しようとしたタスクから送出)。

結果を待ちたくないこともあるかも知れないので、結果が到着済か future に問い合わせることもできる:


	if (f.wait_for(0)) {	// get() すべき値が存在する
		// 何かする
	}
	else {
		// 何か他のことをする
	}
しかしながら、future の主目的は get() を単純にすることだ。

promise の主目的は、futureget() と対になる『put』(珍しいが『set』とも呼ばれる) を単純にすることだ。 『future』と『promise』という名前は歴史的な理由によるものなので、文句を言わないで欲しい。 ダジャレの豊かな源でもあることだし。

promise から X 型の結果を future に送る (戻す) 必要がある場合、基本的にできることは二つある: 値を渡すか例外を渡すかだ。


	try {
		X res;
		// res の値を計算
		p.set_value(res);
	}
	catch (...) {	// おっと: res を計算できなかった
		p.set_exception(std::current_exception());
	}

ここまでは良いとして、どのようにして、こちらの thread とあちらの thread とで、future/promise のペアを合致させるのか? ええと、futurepromise は移動できる (コピーはできない) ので、広範な可能性がある。 明らかに分かることは、結果を配置するための場所として繋がっている future が保持されている間は、スレッドを作成して、promise を与えるタスクが誰にとっても必要だろうということだ (訳文推敲中: The most obvious idea is for whoever wants a task done to create a thread and give the promise to it while keeping the corresponding future as the place for the result.)。 async() を利用することが、このテクニックのもっとも極端/エレガントな別解だ。

packaged_task 型は単純にタスクを実行するスレッドを起動するために提供されている。 特に、promise に繋がっている future のセットアップを取り扱い、タスクから promise に戻り値や例外を置くためのラッパーコードを提供する。 例えば:


	double comp(vector<double>& v)
	{
		// タスクをパッケージ化:
		// (このタスクは double の配列に対して標準 accumulate() すること):
		packaged_task<double(double*,double*,double)> pt0{std::accumulate<double*,double*,double>};
		packaged_task<double(double*,double*,double)> pt1{std::accumulate<double*,double*,double>};

		auto f0 = pt0.get_future();	// future の在処を取得
		auto f1 = pt1.get_future();

		pt0(&v[0],&v[v.size()/2],0);	// スレッドを開始
		pt1(&v[v.size()/2],&v[size()],0);
	
		return f0.get()+f1.get();	// 結果を取得
	}

以下も参照


std::async()

単純なタスク起動関数 async() は、標準案への取込投票に掛けられていない、この FAQ の中で唯一の機能だ。 些細な違いがある別の二案との調整の後、10 月 (訳注: 2008 年か?) の投票に掛けられるだろう (本当に投票されたかどうかは近場の委員会メンバに遠慮なく聞いて欲しい)。

ここに挙げる例は、並列プログラミングのごたごたしたスレッド + ロックをプログラマに思いとどまらせる方法だ:


	template<class T, class V> struct Accum  {	// 単純な累算関数オブジェクト
		T* b;
		T* e;
		V val;
		Accum(T* bb, T* ee, const V& v) : b{bb}, e{ee}, val{vv} {}
		V operator() () { return std::accumulate(b,e,val); }
	};

	double comp(vector<double>& v)
		// v が十分大きい場合、多くの子タスクが起動
	{
		if (v.size()<10000) return std::accumulate(v.begin(),v.end(),0.0);

		auto f0 {async(Accum{&v[0],&v[v.size()/4],0.0})};
		auto f1 {async(Accum{&v[v.size()/4],&v[v.size()/2],0.0})};
		auto f2 {async(Accum{&v[v.size()/2],&v[v.size()*3/4],0.0})};
		auto f3 {async(Accum{&v[v.size()*3/4],&v[v.size()],0.0})};

		return f0.get()+f1.get()+f2.get()+f3.get();
	}
これは非常に純朴な並列プログラミングの利用だが (『マジックナンバー』に注意)、明示的に threadlock、バッファ等がないことに注意されたい。 f-変数の型は、future となる標準ライブラリ関数 async() の戻り値型によって決まる。 必要なら、futureget()thread の完了まで待機する。 ここで、async() の仕事は必要な子 thread を起動することであり、future の仕事は適当な threadjoin() することだ。 『単純』であることは async()/future の設計においてもっとも重要な観点だ; future は一般的に thread として使うこともできるが、async() を I/O や mutex の操作やその他の方法で別のタスクと相互作用するタスクの起動に使おうと考えることすらしてはいけない。 async() の背景にある考えは、範囲-for 文の背景にある考えと同じだ: もっとも単純な例を扱う単純な方法を提供し、更に複雑な例は完全に一般的な仕組みにお任せすることだ。

async() は、新しい thread や、呼出元以外のあらゆる thread、あるいは async() がそれを良い考えだと『思う』場合に限り、異なる thread でも起動要求されることがある。 後者は、ユーザの視点からはもっとも単純であり、潜在的にはもっとも効率的だ (単純なタスクに関する限り)。

以下も参照


プロセスの中断

申し訳ないが、この項目を書く時間がない。 また後日確認されたい。


乱数生成器

乱数は、試験、ゲーム、シミュレーション、セキュリティ等、多くの場面で役に立つ。 アプリケーション領域の多様性は標準ライブラリが提供する乱数生成器の選択肢の広さにつながる。 乱数生成器は、乱数値や疑似乱数値の数列を生成するエンジン部分と、ある範囲内での数学的な分布にその値を割り当てる分布部分の二つからなる。 分布の例としては、uniform_int_distribution (全ての整数が均等に生成される) や normal_distribution (『釣鐘型曲線』) があり、各々に特定の範囲がある。 例えば:

	uniform_int_distribution<int> one_to_six {1,6};  // 分布は 1..6 の int に割り当てられる
	default_random_engine re {};        // 既定のエンジン
乱数を取得するには、エンジン付きで分散を呼び出せばよい:

        int x = one_to_six(re);	// x は [1:6] の範囲になる
呼出毎に毎回エンジンを渡すのは飽き飽きするだろうから、引数なしで呼び出せる関数オブジェクトを得るための引数を bind できる:

	auto dice {bind(one_to_six,re)};	// 乱数生成器の作成

	int x = dice();	// サイコロを振る: x は [1:6] の範囲になる
一般性と効率性に対する妥協のないこだわりのおかげで、標準ライブラリの乱数コンポーネントは『全ての乱数ライブラリが収まるまでに巨大化した』と、ある専門家に評されるようになった。 しかしながら、このことは『初心者に優しく』ないと指弾されるかも知れない。 著者は乱数インターフェースが性能上のボトルネックになったことなど全く見たことがないのだが、非常に単純な乱数生成器を必要としない初心者 (どんな背景を持つにせよ) を教えたことはない。 以下のようなもので十分だろう

	int rand_int(int low, int high);	// [low:high]の範囲で一様に分布する乱数を生成
それでは、その値をどのようにして得るのか? rand_int() の中で dice() のような何かを得る必要がある:

	int rand_int(int low, int high)
	{
		static default_random_engine re {};
		using Dist = uniform_int_distribution<int>;
		static Dist uid {};
		return uid(re, Dist::param_type{low,high});
	}

この定義はまだ『上級者レベル』だが rand_int()使用だけなら C++ コースの最初の一週間で扱える。

自明でない例を見せるためだけに、ここに正規分布を生成して出力するプログラムを用意した:

 
	default_random_engine re;   // 既定のエンジン
	normal_distribution<int> nd(31 /* 平均 */,8 /* 標準偏差 */);

	auto norm = std::bind(nd, re);

	vector<int> mn(64);

	int main()
	{
		for (int i = 0; i<1200; ++i) ++mn[round(norm())]; // 生成
	
		for (int i = 0; i< mn.size(); ++i) {
			cout << i << '\t';
			for (int j=0; j<mn[i]; ++j) cout << '*';
			cout << '\n';
		}
	}
結果は以下の通りだ:

0	
1	
2	
3	
4	*
5	
6	
7	
8	
9	*
10	***
11	***
12	***
13	*****
14	*******
15	****
16	**********
17	***********
18	****************
19	*******************
20	*******************
21	**************************
22	**********************************
23	**********************************************
24	********************************************
25	*****************************************
26	*********************************************
27	*********************************************************
28	***************************************************
29	******************************************************************
30	**********************************************
31	*********************************************************************
32	**********************************************
33	*************************************************************
34	**************************************************************
35	***************************************
36	***********************************************
37	**********************************************
38	*********************************************
39	********************************
40	********************************************
41	***********************
42	**************************
43	******************************
44	*****************
45	*************
46	*********
47	********
48	*****
49	*****
50	****
51	***
52	***
53	**
54	*
55	*
56	
57	*
58	
59	
60	
61
62
63

以下も参照


正規表現

申し訳ないが、この項目を書く時間がない。 また後日確認されたい。

以下も参照


Concept

警告: 「concepts」は C++11 には含まれておらず、徹底的に再設計中である

「concept」は、型や、型同士の組み合わせ、型と整数の組み合わせに必要であることを表現するための仕掛けだ。 これは特に、template の使用の早期チェックを行うのに便利だ。 また逆に、template 本体の早期エラー検出の助けにもなる。 標準ライブラリのアルゴリズム fill を考えよ:

	template<ForwardIterator Iter, class V>		// 型の型
		requires Assignable<Iter::value_type,V>	// 引数型同士の関係
	void fill(Iter first, Iter last, const V& v);	// 宣言のみ、定義なし


	fill(0, 9, 9.9);		// Iter は int なので、エラー: int は ForwardIterator でなく
					//                     int には前置 * がない
	fill(&v[0], &v[9], 9.9);	// Iter は int*、ok: int* は ForwardIterator

fill() は宣言しただけで、定義 (実装) していないことに注意されたい。 一方で、fill() が引数から必要とするものは明示的に言明されている: 我々はもちろん、標準規格を読んだことがあり、そのことを知っている。 しかしながら、コンパイラは必須要件のドキュメントを読まないので、コードで ForwardIteratorAssignable の concept を使って、それを伝える必要がある。 結果として、fill() 使用のエラーはそれを使用した箇所で捕捉され、そのエラーメッセージも大きく改善される。 今やコンパイラはプログラマの意図に関する情報を得て、良いチェックや良い診断が可能になったのだ。

template の実装者も concept の恩恵を受ける。 以下を考えよ:

	template<ForwardIterator Iter, class V>
		requires Assignable<Iter::value_type,V>
	void fill(Iter first, Iter last, const V& v)
	{
		while (first!=last) {
			*first = v;
			first=first+1;	// エラー: + は ForwardIterator では定義されない
					// (++first を使用)
		}
	}
このエラーは直ちに捉えられ、大量の退屈なテストが不要になる (もちろん全部のテストではないが)。

異なる型の型を分類し、区別できるようになったことで、渡すべき型の種類に基づいたオーバーロードが可能になる。 例えば

	// イテレータベースの標準ソート (concept 付き):
	template<Random_access_iterator Iter>
		requires Comparable<Iter::value_type>
	void sort(Iter first, Iter last); // 通常の実装を使用

	// コンテナベースのソート:
	template<Container Cont>
		requires Comparable<Cont::value_type>
	void sort(Cont& c)
	{
		sort(c.begin(),c.end());    // イテレータ版の単純な呼び出し
	}

	void f(vector<int>& v)
	{
		sort(v.begin(), v.end());   // ある方法
		sort(v);                    // もう一つの方法
		// ...
	}

自分用の concept を定義することも可能だが、初心者のために ForwardIteratorCallableLessThanComparableRegular といった様々な便利な concept を標準ライブラリが提供している。

メモ: C++0x 標準ライブラリは concept を用いて規定されている。

以下も参照


Concept map

int*ForwardIterator である。 concept を説明する時に著者達はそう言ったし、標準ライブラリも常にそう言ってきたし、イテレータにポインタを使っていた最初のバージョンの STL ですらそうだった。 しかしながら、ForwardIteratorvalue_type についても話してきたが、int* には value_type メンバがないし、そもそもメンバは一つもない。 では、int* はどうして ForwardIterator 足り得るのか? 著者達がそう言っているから、というのがその理由だ。 concept_map を使うことで、ForwardIterator が要求される場所で T* を使えるかを明示できる。 T とその value_type を考えよう:

	template<Value_type T> 
	concept_map ForwardIterator<T*> {	  // T* の value_type は T
		typedef T value_type;
	};
concept_map があれば、どのようにして型を参照したいかを示すことができ、修正したり新しい型にラップする必要もない。 「concept map」は、汎用用途を目的として個々に開発されたソフトウェアをつなぐ、非常に柔軟で一般性のある仕組みなのだ。


Axiom

axiom は concept のセマンティクスを指定する述語の集合だ。 axiom の主な利用場面は、分野依存の最適化ツールのような外部ツール (一般的なコンパイラの動作ではない) になる (プログラム変換を仕樣化する言語が axiom の大きな動機の一つだ)。 第二の利用場面は、単純に標準のセマンティクスの仕樣の厳密化だ (標準ライブラリ仕樣の多くの箇所でそのために使われている)。 axiom はある種の最適化 (コンパイラや伝統的なオプティマイザが行う) でも有用かも知れないが、コンパイラはユーザ定義の axiom の情報を解する必要はない。 コンパイラは標準規格で定義されたセマンティクスを拠り所にして動作するからだ。

axiom は等価と考えられる演算のペアを列挙したものだ。 以下を考えよ:

	concept Semigroup<typename Op, typename T> : CopyConstructible<T> {
		T operator()(Op, T, T);
		axiom Associativity(Op op, T x, T y, T z) {
			op(x, op(y, z)) <=> op(op(x, y), z);	// T の演算子は結合的 (associative) であると仮定
		}
	}

	concept Monoid<typename Op, typename T> : Semigroup<Op, T> {	// モノイド (monoid) は単位元 (identity element) を持つ半群 (semigroup)
		T identity_element(Op);
		axiom Identity(Op op, T x) {
			op(x, identity_element(op)) <=> x;
			op(identity_element(op), x) <=> x;
		}
	}
この <=> は等価演算子であり、axiom でだけ用いる。 axiom の証明は (一般に) できないことに注意すること。 証明できないことを記述するために axiom を使うからだが、プログラマが記述できるのは許容され得る仮定になる。 等価文の両辺は値によっては非合法になり得ることに注意すること。 例えば、浮動小数点数における NaN (非数値) がそうだ: もし等価文の両辺が共に NaN の場合は (明らかに) 両辺とも無効かつ等価になる (axiom の記述とは無関係に) が、片方だけが NaN の場合は axiom の利点が生きるかも知れない。

axiom は等価文 (<=> を用いた) と条件文 (「if (何とか) 以降の等価を仮定」の形式) の羅列だ:

	// concept TotalOrder 中で:
	axiom Transitivity(Op op, T x, T y, T z)
	{
		if (op(x, y) && op(y, z)) op(x, z) <=> true;	// 条件付きで等価
	}
以下も参照

Morgan Stanley | Columbia 大学 | チャーチル・カレッジ, ケンブリッジ

ホーム | C++ | FAQ | 技術的 FAQ | 出版物 | WG21 文書 | プログラミング言語 C++ | Tour++ | プログラミング | C++ の設計と進化 | 略歴 | インタビュー | 動画 | 引用 | アプリケーション | ガイドライン | コンパイラ