Writing modern C++ code: how C++ has evolved over

•
この PowerPoint ファイルには、「ノート」 セクションにセッションの講師が話し
ている内容を書き起こしたもの (トランスクリプト) を入力しています。
•
ノートを参照するには、PowerPoint の表示モードを [標準] または [ノート] に設定
してください。[標準] の場合は、スライド表示ウィンドウの下 (ノート ペイン) に
表示されます。
•
ノート表示モードで見た際にノートが 1 ページに収まりきらない場合は、スライ
ドを複製して複数ページにわたってノートを入力しています。そのため、オリジ
ナルの英語版ファイルと比較して、スライド番号やスライドの枚数が異なる場合
があります。(本スライドが追加されている時点で、英語版とは枚数が異なります)
•
ノートを印刷するには、[印刷プレビュー] または [印刷] 画面において、[印刷対象]
を [ノート] に指定してください。
•
本プレゼンテーション (以下、本書) で提供されている情報は、本書が
発表された時点における Microsoft の見解を述べたものです。市場
ニーズの変化に対応する必要があるため、本書は記載された内容の実
現に関する Microsoft の確約とはみなされないものとします。また本
書に記載された情報の正確さについて、保証するものではありません。
•
本書は情報の提供のみを目的としており、明示または黙示に関わらず、
本書について Microsoft はいかなる保証をするものでもありません。
•
本書に記載されている機能名や用語の日本語訳は、あくまでも暫定的
なものであり、将来変更される可能性があります。
ロードマップ

このセッションの動機と範囲

最新の C++: クリーン、安全、高速

モジュール間の接続について: ABI セーフ、他言語

まとめ
動機と目的

開発者たちの間で C++ への
回帰が広がる




プログラミング経験のある方
C++ の変更点に関する知識が
ある方
最新の C++ の洗練された
コーディング方法を知らない方
最新の C++ による、
クリーンで、安全で、高速な
コーディング方法を説明
性能:
あらゆる規模で稼働 –
オンチップ、モバイル、
デスクトップ、データセンター
サイズ:
プロセッサ リソースの制限
– デスクトップ、モバイル
エクスペリエンス:
小型のハードウェアで
高度なエクスペリエンス
を実現
常識を打ち破るには、
あらゆるサイクルが
重要に
C++ の価値に対する考え方

C++ の価値提案である効率的な抽象化を実現



強力な抽象化: タイプセーフなオブジェクト指向と汎用コードによる強力な
モデル化、制御性も効率性も犠牲にしない
コードとメモリの完全制御: 実行したい処理を常に表現可能
メモリとデータのレイアウトを常に厳密に制御可能
従量課金のような効率性: 強制的なオーバーヘッドがなく、必要な分だけ作業
コストが発生
「Facebook では『合理的に記述された C++ コードは高速である』と認識
されており、PHP と Java コードの最適化に多大な努力が費やされたことを
物語っています。C++ は他言語と比べて記述が複雑ですが、
効率的なコードを書くのはずっと簡単です」– Andrei Alexandrescu
ロードマップ

このセッションの動機と範囲

最新の C++: クリーン、安全、高速

モジュール間の接続について: ABI セーフ、他言語

まとめ
変更点: 概要
auto による型の省略
T*  shared_ptr<T>
new  make_shared
以前
現在
circle* p = new circle( 42 );
auto p = make_shared<circle>( 42 );
vector<shape*> vw = load_shapes();
vector<shared_ptr<shape>> vw = load_shapes();
for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i ) {
if( *i && **i == *p )
cout << **i << “ is a match\n”;
}
for_each( begin(vw), end(vw), [&]( shared_ptr<circle>& s ) {
if( s && *s == *p )
cout << *s << “ is a match\n”;
} );
for/while/do 
std::アルゴリズム
[&] ラムダ関数
for( vector<circle*>::iterator i = vw.begin();
i != vw.end(); ++i ) {
delete *i;
非例外安全
}
delete p;
try/catch、__try/__finally
がない
“delete” は不要
有効期間の自動管理
例外安全
変更点: 概要 (続き)
auto による型の省略
T*  shared_ptr<T>
new  make_shared
以前
現在
circle* p = new circle( 42 );
auto p = make_shared<circle>( 42 );
vector<shape*> vw = load_shapes();
vector<shared_ptr<shape>> vw = load_shapes();
for( vector<circle*>::iterator i = vw.begin(); i != vw.end(); ++i ) {
if( *i && **i == *p )
cout << **i << “ is a match\n”;
}
for_each( begin(vw), end(vw), [&]( shared_ptr<circle>& s ) {
if( s && *s == *p )
cout << *s << “ is a match\n”;
} );
for/while/do 
std::アルゴリズム
[&] ラムダ関数
for( vector<circle*>::iterator i = vw.begin();
i != vw.end(); ++i ) {
delete *i;
非例外安全
}
delete p;
try/catch、__try/__finally
がない
“delete” は不要
有効期間の自動管理
例外安全
素晴らしいものは、変わらない:
自動有効期間 = 効率 + 例外安全
class widget {
private:
gadget g;
public:
void draw();
};
有効期間は自動的に
格納先のオブジェクトに
結び付けられる
リークなし、例外安全
void f() {
widget w;
:::
w.draw();
:::
}
有効期間は自動的に
スコープに結び付けられる
w を生成 (gadget メンバーの
w.g も含む)
w と w.g を自動的に
破棄/解放
自動的に例外安全
“finally {
w.dispose();
w.g.dispose(); }”
ヒープの有効期間: 標準スマート ポインター
class gadget;
共有
自動有効期間管理に
よって gadget を所有
class widget {
リークなし、例外安全
private:
shared_ptr<gadget> g;
};
class gadget {
private:
weak_ptr<widget> w;
};
参照カウントを
行いたくない場合は
weak_ptr を使用
node が子要素を所有
リークなし、例外安全
class node {
vector<unique_ptr<node>> children;
node* parent;
:::
node は親を保持
public:
node( node* parent_)
: parent(parent_)
{
children.push_back( new node(…) );
:::
}
“new” はそれを所有する
};
パフォーマンスの最適化が必要なとき、所有する * や
delete をカプセル化して使用することを検討
(隠しオブジェクトなど)
例: 独自の低レベル データ構造を記述
単有
別のオブジェクト
(通常は unique_ptr) を
直ちに初期化
ヒープの有効期間: 標準スマート ポインター (続き)
class gadget;
共有
自動有効期間管理に
よって gadget を所有
class widget {
リークなし、例外安全
private:
shared_ptr<gadget> g;
};
class gadget {
private:
weak_ptr<widget> w;
};
参照カウントを
行いたくない場合は
weak_ptr を使用
node が子要素を所有
リークなし、例外安全
class node {
vector<unique_ptr<node>> children;
node* parent;
:::
node は親を保持
public:
node( node* parent_)
: parent(parent_)
{
children.push_back( new node(…) );
:::
}
“new” はそれを所有する
};
パフォーマンスの最適化が必要なとき、所有する * や
delete をカプセル化して使用することを検討
(隠しオブジェクトなど)
例: 独自の低レベル データ構造を記述
単有
別のオブジェクト
(通常は unique_ptr) を
直ちに初期化
「C++ はガベージ コレクションに最も適した言語だ。
その用があまりないのだから」
— Bjarne Stroustrup
コンテナー
vector<string> v;
v.push_back( “Geddy Lee” );
既定のコンテナー: ベクター
コンパクトで効率的: キャッシュや
プリフェッチャーに対応
array<string,50> a;
固定サイズ ベクター: 配列
コンパクトで効率的: キャッシュや
プリフェッチャーに対応
ディクショナリ: map (ツリー)
または unordered_map (ハッシュ)
map<string, string> phone;
phone[“Alex Lifeson”] = “+1 (416) 555-1212”;
multimap<string, string> phone;
phone[“Neil Peart”] = “+1 (416) 555-1212”;
phone[“Neil Peart”] = “+1 (905) 555-1234”;
unordered_map<string, string> phone;
phone[“Alex Lifeson”] = “+1 (416) 555-1212”;
unordered_multimap<string, string> phone;
phone[“Neil Peart”] = “+1 (416) 555-1212”;
phone[“Neil Peart”] = “+1 (905) 555-1234”;
コンテナー (続き)
vector<string> v;
v.push_back( “Geddy Lee” );
既定のコンテナー: ベクター
コンパクトで効率的: キャッシュや
プリフェッチャーに対応
array<string,50> a;
固定サイズ ベクター: 配列
コンパクトで効率的: キャッシュや
プリフェッチャーに対応
ディクショナリ: map (ツリー)
または unordered_map (ハッシュ)
map<string, string> phone;
phone[“Alex Lifeson”] = “+1 (416) 555-1212”;
multimap<string, string> phone;
phone[“Neil Peart”] = “+1 (416) 555-1212”;
phone[“Neil Peart”] = “+1 (905) 555-1234”;
unordered_map<string, string> phone;
phone[“Alex Lifeson”] = “+1 (416) 555-1212”;
unordered_multimap<string, string> phone;
phone[“Neil Peart”] = “+1 (416) 555-1212”;
phone[“Neil Peart”] = “+1 (905) 555-1234”;
ループ処理
for/while/do 
std::アルゴリズム
[&] ラムダ関数
以前
現在
for( auto i = v.begin(); i != v.end(); ++i ) {
:::
:::
任意長のラムダ本体。
:::
ループ本体を
}
ラムダの中に配置
for_each( begin(v), end(v), []( string& s ) {
:::
for_each で各要素にアクセス
:::
:::
} );
auto i = v.begin();
for( ; i != v.end(); ++i ) {
if (*i > x && *i < y) break;
}
auto i = find_if( begin(v), end(v),
[=](int i) { return i > x && i < y; } );
find_if で一致する要素を検索
非メンバーの
begin()/end() を使用
アルゴリズム

既定で以下を使用:

for_each: 既定のトラサーバル アルゴリズム

not-in-place セマンティクスでは transform を使用

find_if: 既定の検索アルゴリズム

sort、lower_bound など: 既定のソートおよび検索機能
比較演算子の記述: 厳格な < を使用。名前付きラムダを使用

auto comp = []( const widget& w1, const widget& w2 ) { return w1.weight() < w2.weight(); }
sort( v.begin(), v.end(), comp );
auto i = lower_bound( v.begin(), v.end(), comp );
値型と参照型
基底クラスと仮想関数
が重要
“コピー可能な” 値型 (既定)
“ポリモーフィック” 参照型
class point {
int x;
int y;
public:
:::
};
class shape : boost::noncopyable {
public:
明示的にコピーを無効化
virtual draw();
:::
};
無効化は継承される
メモリとレイアウトの制御
が重要
class circle : shape {
public:
virtual draw() override;
:::
};
明示的な
オーバーライド制御
値型と参照型 (続き)
基底クラスと仮想関数
が重要
“コピー可能な” 値型 (既定)
“ポリモーフィック” 参照型
class point {
int x;
int y;
public:
:::
};
class shape : boost::noncopyable {
public:
明示的にコピーを無効化
virtual draw();
:::
};
無効化は継承される
メモリとレイアウトの制御
が重要
class circle : shape {
public:
virtual draw() override;
:::
};
明示的な
オーバーライド制御
値型とムーブの効率性
set<widget> load_huge_data() {
set<widget> ret;
// … データを読み込み、ret に設定 …
return ret;
}
widgets = load_huge_data();
効率的、ディープ コピー
は行わない
“ヒープ割り当てと
ポインター戻し” は不要
vector<string> v = IfIHadAMillionStrings();
v.insert( begin(v)+v.size()/2, “tom” );
v.insert( begin(v)+v.size()/2, “richard” );
v.insert( begin(v)+v.size()/2, “harry” );
効率的、ディープ コピーは行わない
(150 万 ptr/len 回の代入)
HugeMatrix operator+(
const HugeMatrix&,
const HugeMatrix&
);
hm3 = hm1+hm2;
効率的、余分なコピーは行わない
値型とムーブの効率性 (続き)
set<widget> load_huge_data() {
set<widget> ret;
// … データを読み込み、ret に設定 …
return ret;
}
widgets = load_huge_data();
効率的、ディープ コピー
は行わない
“ヒープ割り当てと
ポインター戻し” は不要
vector<string> v = IfIHadAMillionStrings();
v.insert( begin(v)+v.size()/2, “tom” );
v.insert( begin(v)+v.size()/2, “richard” );
v.insert( begin(v)+v.size()/2, “harry” );
効率的、ディープ コピーは行わない
(150 万 ptr/len 回の代入)
HugeMatrix operator+(
const HugeMatrix&,
const HugeMatrix&
);
hm3 = hm1+hm2;
効率的、余分なコピーは行わない
適切な値型でムーブを有効にする
class my_class {
unique_ptr<BigHugeData> data;
public:
my_class( my_class&& other )
: data( move( other.data ) ) { }
my_class& operator=( my_class&& other )
{ data = move( other.data ); }
ムーブ コンストラクター
ムーブ代入演算子
:::
void method() {
if( !data ) throw “moved-from object”;
:::
チェック (必要な場合)
}
};
? ムーブ: ディープ コピーより
コピー 
処理が軽ければムーブを有効化
ムーブ 
/ コピー: 一部の 非値型は
ムーブのみ対応。例: unique_ptr
ロードマップ

このセッションの動機と範囲

最新の C++: クリーン、安全、高速

モジュール間の接続について: ABI セーフ、他言語

まとめ
Pimpl によるコンパイル時のカプセル化 (C++  C++)

Pimpl イディオムを賢く活用して private メンバーを隠ぺいする
class my_class {
// … public および protected メンバーはここで宣言 …
private:
class impl; unique_ptr<impl> pimpl; // 不透明な型はこちら
};
class my_class::impl {
// private で定義
// … private のデータおよび関数:
// 呼び出し元を再コンパイルせずに変更可能 …
};
my_class::my_class() : pimpl( new impl )
{
/* … impl 値を設定 …*/
}


カスケードの再構築とオブジェクト レイアウトの脆弱性を回避
(推移的な) 使用頻度の高い型の場合に最も適切
my_class.h
my_class.cpp
ABI では十分に移植性のある型と規約を使用 (C++  * )

移植性のある型 = C 組み込み型 (* を含む) および構造体


クラス型を使用できるのは、呼び出し元と呼び出し先がレイアウトや呼び出し
規約などに合意している場合に限る = 同一のコンパイラ + 設定によるコンパイル
呼び出し元が別のコンパイラ/言語でコンパイルされている場合:

特定の呼び出し規約で “extern C” API に変換
class widget {
widget();
~widget();
double method( int, gadget& );
extern “C” {
// 明示的な “this” を関数で使用
struct widget;
// 不透明な型を使用 (前方宣言のみ)
widget* STDCALL widget_create();
// ctor  “this” を作成
void STDCALL widget_destroy( widget* );
// dtor  “this” を破棄
double STDCALL widget_method( widget*, int, gadget* ); //“this” を使用
};
}
WinRT の型: クロス言語での使用 (C++  JS/.NET )
C/C++ の
外部サーフェス
WinRT の
外部サーフェス
“C” handle スタイル、
C++ Pimpl スタイルを使用
WinRT の呼び出し元/
呼び出し先
モジュールの
内部処理
C++ で作成
C++ と WinRT
型の種類を明示可能:
値型、参照型、インターフェイス
標準 C++: 移植性と効率性に優れた型
C++/CX: WinRT と ABI セーフな型
class point { int x; int y; };
class drawable : boost::noncopyable {
public: virtual void draw() = 0;
};
class shape : public drawable { … };
class circle : public shape { … };
value class Point { int x; int y; };
interface class IDrawable {
virtual void Draw();
};
ref class Shape : IDrawable { … };
ref class Circle : Shape { … };
:::
:::
auto p = make_shared<circle>();
shared_ptr<drawable> p2 = p;
p2->draw();
auto p = ref new Circle();
IDrawable^ p2 = p;
p2->draw();
型は ABI セーフかつ
WinRT とのクロス言語
2 つの主な概念:
^ と ref new
ロードマップ

このセッションの動機と範囲

最新の C++: クリーン、安全、高速

モジュール間の接続について: ABI セーフ、他言語

まとめ
C++ への回帰
C++ が再び業界の注目を集める
 マイクロソフトは C++ へのコミットメントを刷新:





Windows 8 向けの新しいプログラミング モデル
CPU と GPU のパワーをフル活用
Windows 8 のハードウェア機能をフル活用
ARM 対応
Visual C++: Windows のパワーとパフォーマンスを備えたツール
関連セッション
CHANNEL 9 のオンライン セッション
• TOOL-100T: Improving software quality using Visual
• Bringing Existing C++ Code into Metro Style Apps
• TOOL-479T: A lap around Visual Studio 11 Express
• Under the Covers with C++ for Metro style Apps
• TOOL-532T: Using the Windows Runtime from C++
• Building Metro style apps with HTML5 and
Studio 11 C++ Code Analysis
for Metro style apps using C++
• TOOL-761T: A lap around DirectX game
development tools
• TOOL-802T: Taming GPU compute with C++ AMP
• TOOL-845T: Tips and tricks for developing Metro
style apps using C++
Ale Contenti
Deon Brewis
Compiled Code
Raman Sharma
• Why C++: C++ Renaissance
Herb Sutter
Q&A
http://forums.dev.windows.com
http://bldw.in/SessionFeedback