157
Ryo Suzuki @Reputeless 2013.9.14 全日本学生ゲーム開発者連合(全ゲ連) 第 14 回交流会 v1.03 Siv3D 開発者 早稲田大学

ゲーム開発者のための C++11/C++14

Embed Size (px)

DESCRIPTION

第14回 全ゲ連での講演資料です。 Twitter: @Reputeless

Citation preview

Page 1: ゲーム開発者のための C++11/C++14

Ryo Suzuki @Reputeless

2013.9.14 全日本学生ゲーム開発者連合(全ゲ連) 第 14回交流会v1.03

Siv3D 開発者 早稲田大学

Page 2: ゲーム開発者のための C++11/C++14
Page 3: ゲーム開発者のための C++11/C++14

1

2𝜋𝜎2𝑒𝑥𝑝 −

𝑥 − 𝜇 2

2𝜎2

正規分布とゲーム

Page 4: ゲーム開発者のための C++11/C++14

正規分布とゲーム

Page 5: ゲーム開発者のための C++11/C++14

正規分布とゲーム

Page 6: ゲーム開発者のための C++11/C++14

正規分布とゲーム

Page 7: ゲーム開発者のための C++11/C++14

ゲームで現実味のあるランダムな結果をつくるとき正規分布が役に立つ

正規分布とゲーム

Page 8: ゲーム開発者のための C++11/C++14

C++11では正規分布する乱数を簡単につくる機能が追加

Page 9: ゲーム開発者のための C++11/C++14

A Proposal to Add an Extensible Random Number Facility to the Standard Library (Revision 2) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1452.html

Page 10: ゲーム開発者のための C++11/C++14

ゲーム開発者にとって優しく便利になった最新の C++

Page 11: ゲーム開発者のための C++11/C++14

最新の C++ でゲーム開発をするための 14 のガイドライン

Page 12: ゲーム開発者のための C++11/C++14

C++の進化

Page 13: ゲーム開発者のための C++11/C++14

C++98major

C++03bug fix only

C++11major

C++14minor

C++17major

C++11 は13年ぶりのアップデート

Page 14: ゲーム開発者のための C++11/C++14

C++11/14での進化

• コードを短く簡単にする

• 間違いやすさを減らす

• 実行時性能を向上させる

• 機能を増やす

Page 15: ゲーム開発者のための C++11/C++14

Visual Studioは着実にC++11/14に対応

2010. 4 2010auto, move, nullptrlamdas, <random>

2012. 9 2012Range-based for, enum class

<chrono> , <ratio>. <thread>

2013. 6 2013 PreviewVariadic templates

initializer_lists, C++14 libs

2013. 9 2013 RCNon-static data member init

defaulted / deleted functions2013. 11 2013

2013 Q4 2013 + CTPconstexpr, noexcept

C++14 generic lamdas

Page 16: ゲーム開発者のための C++11/C++14

Visual Studio 2010/2012/2013でサポートされている機能を対象

Page 17: ゲーム開発者のための C++11/C++14

最新の C++ でゲーム開発をするための 14 のガイドライン

Page 18: ゲーム開発者のための C++11/C++14

新しい乱数ライブラリを使おう

1.

Page 19: ゲーム開発者のための C++11/C++14

<random> ヘッダの乱数エンジンは高品質な乱数生成器を提供する

適切な分布クラスを定義することで、乱数の型、範囲、分散のしかたを簡単にコントロールできる

要約

Page 20: ゲーム開発者のための C++11/C++14

従来の rand() の欠点

• 最大値が 32767 と小さい (Visual Studio)

• 偏りが生じやすい

• 型や分布を柔軟に指定できない

Page 21: ゲーム開発者のための C++11/C++14

新しい乱数ライブラリ<random> ヘッダに定義

乱数エンジン

メルセンヌ・ツイスター法やハードウェアエントロピーによる乱数生成器

分布クラス

乱数の型と範囲、分散方法を定義

Page 22: ゲーム開発者のための C++11/C++14

mt19937 rng;

for (int i=0; i<10; ++i)

cout << rng() << '¥n';

乱数エンジン [1/3]

メルセンヌ・ツイスター法による乱数生成

Page 23: ゲーム開発者のための C++11/C++14

mt19937 rng(123456);

for (int i=0; i<10; ++i)

cout << rng() << '¥n';

乱数エンジン [2/3]

乱数のシード値を指定

Page 24: ゲーム開発者のための C++11/C++14

random_device rng;

for (int i=0; i<10; ++i)

cout << rng() << '¥n';

乱数エンジン [3/3]

ハードウェア・エントロピー・ソースを基にした予測不能な乱数生成

Page 25: ゲーム開発者のための C++11/C++14

乱数生成器の比較

乱数の質 速度

rand() 低い 早い

mt19937 優秀 早い

random_device 真の乱数 遅い

Page 26: ゲーム開発者のための C++11/C++14

mt19937 rng{ random_device()() };

for (int i=0; i<10; ++i)

cout << rng() << '¥n';

乱数エンジンの工夫random_device で mt19937 のシード作成

Page 27: ゲーム開発者のための C++11/C++14

mt19937 rng;

uniform_int_distribution<int> dist(1,6);

for (int i=0; i<10; ++i)

cout << dist(rng) << '¥n';

// 3 1 3 6 5 2 6 ...

整数の一様分布指定した範囲の整数が等確率で出現

Page 28: ゲーム開発者のための C++11/C++14

mt19937 rng;

uniform_real_distribution<double>

dist(-100.0,100.0);

for (int i=0; i<10; ++i)

cout << dist(rng) << '¥n';

// 62.9447 -72.90463 81.15846 ...

実数の一様分布指定した範囲の実数が等確率で出現

Page 29: ゲーム開発者のための C++11/C++14

ベルヌーイ分布指定した確率で true が出現

mt19937 rng;

bernoulli_distribution dist(0.5);

if (dist(rng))

cout << "おもて¥n";

else

cout << "うら¥n";

Page 30: ゲーム開発者のための C++11/C++14

正規分布平均 μ, 標準偏差 σ の正規分布にしたがって値が出現

mt19937 rng();

normal_distribution<double>

dist(170.0,6.0);

for (int i=0; i<10; ++i)

cout << dist(rng) << '¥n';

Page 31: ゲーム開発者のための C++11/C++14

0.000…% の異常値を避けるために適切にクランプする

正規分布の注意

3m級の巨人

Page 32: ゲーム開発者のための C++11/C++14

<random> ヘッダの乱数エンジンは高品質な乱数生成器を提供する

適切な分布クラスを定義することで、乱数の型、範囲、分散のしかたを簡単にコントロールできる

復習

Page 33: ゲーム開発者のための C++11/C++14

型の宣言はautoに任せよう

2.

Page 34: ゲーム開発者のための C++11/C++14

長い型名や、わかりにくい型名はauto を使って省略しよう

auto を使っていて const や参照型が欲しい場合は、const や & を記述すること

要約

Page 35: ゲーム開発者のための C++11/C++14

auto x = 5; // int

auto y = 3.5f; // float

auto z = sin(3.14); // double

// 実際は上記のような単純な場面では

// 読みにくくなるので使うべきでない

auto [1/4]

宣言した変数の型を右辺の初期化子から静的に推論

Page 36: ゲーム開発者のための C++11/C++14

vector<int>::iterator i

= max_element(v.begin(),v.end());

map<string,pair<int,string>>::iterator k

= m.find("key");

auto [2/4]

長い型名を省略する

Page 37: ゲーム開発者のための C++11/C++14

auto [3/4]

長い型名を省略する

auto i = max_element(v.begin(),v.end());

auto k = m.find("key");

Page 38: ゲーム開発者のための C++11/C++14

const auto x = 5; // const int

vector<vector<int>> vv(10);

auto a = vv[0]; // vector<int>

auto& b = vv[0]; // vector<int>&

const auto& c = vv[0]; // const vector<int>&

auto [4/4]

const 修飾や参照の宣言

Page 39: ゲーム開発者のための C++11/C++14

長い型名や、わかりにくい型名はauto を使って省略しよう

auto を使っていて const や参照型が欲しい場合は、const や & を記述すること

復習

Page 40: ゲーム開発者のための C++11/C++14

範囲ベースのループを使おう

3.

Page 41: ゲーム開発者のための C++11/C++14

範囲ベースのループを使うと、単純なループを短く記述できる

ループカウンタのような不必要な変数を減らし、コードの意図をより明確にしよう

要約

Page 42: ゲーム開発者のための C++11/C++14

int scores[5] = {40,80,90,60,100};

for (auto& score : scores)

score += 10;

for (const auto score : scores)

cout << score << '¥n';

// 50 90 100 70 110

範囲ベースforループ [1/5]

単純な for ループを短くできる

Page 43: ゲーム開発者のための C++11/C++14

範囲ベースforループ [2/5]

イテレーターを返す begin() / end()メンバ関数を持っていれば使える

vector<int> v;

list<double> li;

string str;

for (auto n : v) cout << n << '¥n';

for (auto x : li) cout << x << '¥n';

for (auto ch : str) cout << ch << '¥n';

Page 44: ゲーム開発者のための C++11/C++14

vector<Widget> widgets;

for (auto& widget : widgets)

widget.update();

for (const auto& widget : widgets)

widget.draw();

範囲ベースforループ [3/5]

コピーを避けたい場合は参照で

Page 45: ゲーム開発者のための C++11/C++14

範囲ベースforループ [4/5]

二重ループの改善例

double matrix[4][4] = { ... };

for (int i=0; i<4; ++i)

{

for (int k=0; k<4; ++k)

cout << matrix[i][k] << ',';

cout << '¥n';

}

Page 46: ゲーム開発者のための C++11/C++14

double matrix[4][4] = { ... };

for (const auto& row : matrix)

{

for (const auto elem : row)

cout << elem << ',';

cout << '¥n';

}

範囲ベースforループ [5/5]

二重ループの改善例

Page 47: ゲーム開発者のための C++11/C++14

範囲ベースのループを使うと、単純なループを短く記述できる

ループカウンタのような不必要な変数を減らし、コードの意図をより明確にしよう

復習

Page 48: ゲーム開発者のための C++11/C++14

ラムダ式を使おう

4.

Page 49: ゲーム開発者のための C++11/C++14

ラムダ式で関数オブジェクトをローカルに定義し、アルゴリズムを読みやすくしよう

キャプチャを使うと外部の変数をラムダ式の中で使用できる

要約

Page 50: ゲーム開発者のための C++11/C++14

アルゴリズムは便利だ [1/3]

count_if

find_if

remove_if

for_each

generate

sort ...

第 3 引数に関数

Page 51: ゲーム開発者のための C++11/C++14

bool IsEven(int n) {

return n%2==0;

}

vector<int> v;

// 偶数の要素を数える

size_t x = count_if(v.begin(),v.end(),

IsEven);

アルゴリズムは便利だ [2/3]

Page 52: ゲーム開発者のための C++11/C++14

struct IsEven : unary_function<int,bool> {

result_type operator()

(argument_type n) const {

return n%2==0;

}}; // 関数オブジェクトは関数ポインタより

// インライン化されやすい

vector<int> v;

size_t x = count_if(v.begin(),v.end(),

IsEven());

アルゴリズムは便利だ [3/3]

Page 53: ゲーム開発者のための C++11/C++14

述語関数が面倒だ

使う場所と定義する場所が離れている

関数オブジェクトは記述が長い

これを解決するのがラムダ式

Page 54: ゲーム開発者のための C++11/C++14

size_t x = count_if(v.begin(),v.end(),

[](int n){ return n%2==0; });

ラムダ式 [1/4]

Page 55: ゲーム開発者のための C++11/C++14

size_t x = count_if(v.begin(),v.end(),

[](int n){ return n%2==0; });

ラムダ式 [2/4]

[] () ->T {} で構成される

[] キャプチャリスト

() 引数

->T 戻り値の型(省略可)

{} 関数の本体

Page 56: ゲーム開発者のための C++11/C++14

size_t x = count_if(v.begin(),v.end(),

[](int n){ return n%2==0; });

ラムダ式 [3/4]

ラムダ式は、相当する関数オブジェクトを自動で作る

可読性とパフォーマンスに優れる

Page 57: ゲーム開発者のための C++11/C++14

auto Square =

[](int n){ return n*n; };

cout << Square(9) << '¥n'; // 81

ラムダ式で遊ぼう [1/7]

Page 58: ゲーム開発者のための C++11/C++14

auto PrintSquare =

[](int n){ cout << n*n << '¥n'; };

PrintSquare(100); // 10000

ラムダ式で遊ぼう [2/7]

Page 59: ゲーム開発者のための C++11/C++14

const int ar[4] = { 1, 2, 3, 4 };

for_each(begin(ar),end(ar),

[](int n){ cout << n*n << ' '; });

// 1 4 9 16

ラムダ式で遊ぼう [3/7]

Page 60: ゲーム開発者のための C++11/C++14

const int ar[4] = { 1, 2, 3, 4 };

const int x = 10;

for_each(begin(ar),end(ar),

[=](int n){ cout << n*x << ' '; });

// [=] により、ラムダ式内の x は

// 外部からコピーキャプチャ

// 10 20 30 40

ラムダ式で遊ぼう [4/7]

Page 61: ゲーム開発者のための C++11/C++14

const int ar[4] = { 1, 2, 3, 4 };

int sum = 0;

for_each(begin(ar),end(ar),

[&](int n){ sum += n; });

// [&] により、ラムダ式内の sum は

// 外部から参照キャプチャ

cout << sum << '¥n'; // 10

ラムダ式で遊ぼう [5/7]

Page 62: ゲーム開発者のための C++11/C++14

vector<Vec2> pts;

// 原点に近い順にソート

sort(pts.begin(),pts.end(),

[](const Vec2& a, const Vec2& b)

{ return a.lengthSq()<b.lengthSq(); }

);

ラムダ式で遊ぼう [6/7]

Page 63: ゲーム開発者のための C++11/C++14

vector<Enemy> enemies;

int threshold = 20;

// HP が threshold 未満の敵を削除

enemies.erase(remove_if(

enemies.begin(),enemies.end(),

[=](const Enemy& enemy)

{ return enemy.hp < threshold; }),

enemies.end()

);

ラムダ式で遊ぼう [7/7]

Page 64: ゲーム開発者のための C++11/C++14

ラムダ式で関数オブジェクトをローカルに定義し、アルゴリズムを読みやすくしよう

キャプチャを使うと外部の変数をラムダ式の中で使用できる

復習

Page 65: ゲーム開発者のための C++11/C++14

Emplacementの使い所を知ろう

5.

Page 66: ゲーム開発者のための C++11/C++14

オブジェクトの構築とコンテナへの追加を同時に行う場合は Emplacement を使おう

適切な場面で使えば push_back に比べて要素追加のコストを減らせる

要約

Page 67: ゲーム開発者のための C++11/C++14

vector<Point> v;

v.push_back(Point(5,10));

push_back() のコスト

5 10

COPY

Page 68: ゲーム開発者のための C++11/C++14

vector<Point> v;

v.emplace_back(5,10);

emplace_back()

5 10

Page 69: ゲーム開発者のための C++11/C++14

Emplacement [1/2]

要素のコンストラクタ引数を受け取り、コンテナ内でオブジェクトを構築する

一時オブジェクトのコピーと破棄のコストが発生しない

5 10

Page 70: ゲーム開発者のための C++11/C++14

Emplacement [2/2]

vector, deque, map などのコンテナのEmplacement 挿入関数

push_back() → emplace_back()

push_front() → emplace_front()

insert() → emplace()

Page 71: ゲーム開発者のための C++11/C++14

要素追加の使い分け [1/2]

vector<T> などに対して

push_back()T 型の値 (lvalue / rvalue),{ initializer-lists }

emplace_back()それ以外の型,0 個 もしくは 2 個以上の引数

Page 72: ゲーム開発者のための C++11/C++14

string GetString();

const string str = "Hello";

vector<string> v;

v.push_back(str);

v.push_back(GetString());

v.push_back({ str[0], 'e'});

v.emplace_back("hello");

v.emplace_back();

v.emplace_back(10,'a');

要素追加の使い分け [2/2]

Page 73: ゲーム開発者のための C++11/C++14

オブジェクトの構築とコンテナへの追加を同時に行う場合は Emplacement を使おう

適切な場面で使えば push_back に比べて要素追加のコストを減らせる

復習

Page 74: ゲーム開発者のための C++11/C++14

強く型付けされたenumを使おう

6.

Page 75: ゲーム開発者のための C++11/C++14

enum class は enum の強化版で、強い型付けとスコープを持つ

enum class を使えば、整数型への暗黙的な変換や、列挙子の名前の衝突を防げる

要約

Page 76: ゲーム開発者のための C++11/C++14

void SetColor(unsigned);

enum Team { Red, White };

const unsigned red = 0xffFF0000;

SetColor(red);

SetColor(Red); // ?

従来のenumの問題点 [1/2]

整数型に暗黙的に変換できるため、意図しない振る舞いが可能

Page 77: ゲーム開発者のための C++11/C++14

struct Team {

enum { Red, White };

};

struct Palette {

enum { Red, Green, Blue };

};

従来のenumの問題点 [2/2]

名前の衝突を防ぐためにスコープを作る必要がある

Page 78: ゲーム開発者のための C++11/C++14

enum class name : type {

enumerator = constexpr,enumerator = constexpr, ...

};

enum struct name : type {

enumerator = constexpr,enumerator = constexpr, ...

};

enum class [1/4]

強い型付けとスコープを持つ列挙型

Page 79: ゲーム開発者のための C++11/C++14

enum class Team { Red, White };

enum class Month {

January = 1, February, ...

};

enum class Align : char {

Left = 'L',

Center = 'C',

Right = 'R',

};

enum class [2/4]

Page 80: ゲーム開発者のための C++11/C++14

enum class Team { Red, White };

enum class Palette { Red, Green, Blue };

const Team team = Team::Red;

switch (palette) {

case Palette::Red : break;

case Palette::Green : ...

}

enum class [3/4]

列挙型名のスコープを持つ

Page 81: ゲーム開発者のための C++11/C++14

void SetColor(unsigned);

enum class Team { Red, White };

const unsigned red = 0xffFF0000;

SetColor(red);

SetColor(Team::Red); // error

const int white = Team::White; // error

enum class [4/4]

整数型へ暗黙的に変換されない

Page 82: ゲーム開発者のための C++11/C++14

enum class は enum の強化版で、強い型付けとスコープを持つ

enum class を使えば、整数型への暗黙的な変換や、列挙子の名前の衝突を防げる

復習

Page 83: ゲーム開発者のための C++11/C++14

arrayを活用しよう

7.

Page 84: ゲーム開発者のための C++11/C++14

array は通常の配列にオーバーヘッド無しでコンテナのインタフェースを提供する

array のインタフェースが有効な場面では、積極的に活用しよう

要約

Page 85: ゲーム開発者のための C++11/C++14

配列と array [1/2]

配列はインタフェースが貧弱

const int size = 100;

int ar[size];

for (int i=0; i<size; ++i)

ar[i] = 10 * i;

Page 86: ゲーム開発者のための C++11/C++14

配列と array [2/2]

<array> ヘッダの array を使おう

array<int,100> ar;

for (size_t i=0; i<ar.size(); ++i)

ar[i] = 10 * i;

Page 87: ゲーム開発者のための C++11/C++14

array [1/2]

通常の配列にコンテナのインタフェースを与えたラッパー

size(), at(), begin(), end(), fill() などのメンバ関数を提供

サイズはコンパイル時に決まり、パフォーマンスは通常の配列と変わらない

Page 88: ゲーム開発者のための C++11/C++14

array [2/2]

array<int,5> a = { 5, 10, 15, 20, 25 };

array<int,5> b;

b.fill(100); // 要素を全部 100 に

a = b; // 要素数が同じなら代入可能

a[0] = 0;

for (const auto n : a)

cout << n << '¥n';

Page 89: ゲーム開発者のための C++11/C++14

array は通常の配列にオーバーヘッド無しでコンテナのインタフェースを提供する

array のインタフェースが有効な場面では、積極的に活用しよう

復習

Page 90: ゲーム開発者のための C++11/C++14

NULLをnullptrに置き換えよう

8.

Page 91: ゲーム開発者のための C++11/C++14

ヌルポインタを表す NULL と 0 を nullptrに置き換えよう

ヌルポインタの意図が明確になり、オーバーロードのトラブルを防げる

要約

Page 92: ゲーム開発者のための C++11/C++14

ヌルポインタ [1/3]

NULL

#define NULL 0と定義される、単なる数値の 0

nullptr

あらゆるポインタ型のヌルポインタを表すポインタ定数のキーワード整数には変換できない

C++98

Page 93: ゲーム開発者のための C++11/C++14

ヌルポインタ [2/3]

NULL はトラブルの元

void f(int n);

void f(const char* s);

f(0);

f("hello");

f(NULL); // f(int)

Page 94: ゲーム開発者のための C++11/C++14

ヌルポインタ [3/3]

nullptr でオーバーロードを正確に

void f(int n);

void f(const char* s);

f(0);

f("hello");

f(nullptr); // f(const char*)

Page 95: ゲーム開発者のための C++11/C++14

ヌルポインタを表す NULL と 0 を nullptrに置き換えよう

ヌルポインタの意図が明確になり、オーバーロードのトラブルを防げる

復習

Page 96: ゲーム開発者のための C++11/C++14

右辺値参照を理解しよう

9.

Page 97: ゲーム開発者のための C++11/C++14

右辺値参照と Move セマンティクスによって、サイズが大きいオブジェクトのコピーのパフォーマンスが向上する

自分で定義したクラスにも、必要ならMove セマンティクスを実装できる

要約

Page 98: ゲーム開発者のための C++11/C++14

vector<int> GetVector();

void GetVector(vector<int>& v);

vector<int> v

= GetVector(); // コピーが発生

GetVector(v); // ok

右辺値参照と Move [1/5]

むかーしむかし、大きなオブジェクトを返す関数は御法度だった

Page 99: ゲーム開発者のための C++11/C++14

vector<int> GetVector();

void GetVector(vector<int>& v);

vector<int> v = GetVector(); // ok

GetVector(v); // ok

右辺値参照と Move [2/5]

今はそんなことはない

Page 100: ゲーム開発者のための C++11/C++14

右辺値参照と Move [3/5]

ptr1

ptr2

コピー完了後に破棄

コピー

これまでC++98

Page 101: ゲーム開発者のための C++11/C++14

右辺値参照と Move [4/5]

ptr1

ptr1

所有権を移動(Move セマンティクス)

これから

nullptr

Page 102: ゲーム開発者のための C++11/C++14

右辺値参照と Move [5/5]

右辺値名前のない一時オブジェクト

右辺値参照 (Type&& x)右辺値を受け取るオーバーロード

std::move() 関数左辺値を右辺値にキャスト

Page 103: ゲーム開発者のための C++11/C++14

右辺値参照 実装例 1

struct BigData {

BigData();

BigData(const BigData&);

BigData(BigData && data)

: m_p(data.m_p),m_size(data.m_size) {

data.m_p = nullptr;

data.m_size = 0;

}

~BigData();

int* m_p;

int m_size;

};

Page 104: ゲーム開発者のための C++11/C++14

右辺値参照 実装例 2

struct BigData {

BigData();

BigData(const BigData&);

BigData(BigData && data)

: m_data(move(data.m_data)) { }

vector<int> m_data;

};

Page 105: ゲーム開発者のための C++11/C++14

右辺値参照と Move セマンティクスによって、サイズが大きいオブジェクトのコピーのパフォーマンスが向上する

自分で定義したクラスにも、必要ならMove セマンティクスを実装できる

復習

Page 106: ゲーム開発者のための C++11/C++14

スマートポインタは補助関数で作ろう

10.

Page 107: ゲーム開発者のための C++11/C++14

オブジェクトのポインタはスマートポインタで管理しよう

スマートポインタは補助関数で作って、パフォーマンスの利得と、記述の一貫性を得よう

要約

Page 108: ゲーム開発者のための C++11/C++14

さらばnewとdelete [1/5]

new と delete は危険

int* pArray = new int[10000];

delete[] pArray; // 取扱注意

Page 109: ゲーム開発者のための C++11/C++14

さらばnewとdelete [2/5]

動的配列は vector か string

vector<int> v(10000);

string str;

Page 110: ゲーム開発者のための C++11/C++14

さらばnewとdelete [3/5]

単一のデータのポインタは・・・

Enemy* pEnemy = new Boss;

delete pEnemy;

Page 111: ゲーム開発者のための C++11/C++14

さらばnewとdelete [4/5]

スマートポインタを使う

shared_ptr<Enemy> pEnemy = new Boss;

// 自動的に delete してくれる

// まだ最適化可能

Page 112: ゲーム開発者のための C++11/C++14

unique_ptr<Enemy> pEnemy = new Boss;

// 自動的に delete してくれる

さらばnewとdelete [5/5]

ポインタをコピーしない場合、unique_ptr を使えばゼロオーバーヘッド

Page 113: ゲーム開発者のための C++11/C++14

補助関数 [1/2]

スマートポインタは補助関数で作ろう

make_shared<T>

オブジェクトと管理用データを一緒に連続領域に new するので効率的

make_unique<T>

名前の一貫性、new の記述が不要に

Page 114: ゲーム開発者のための C++11/C++14

補助関数 [2/2]

shared_ptr<Enemy> pEnemy

= make_shared<Boss>();

unique_ptr<Enemy> pEnemy2

= make_unique<Boss>();

Page 115: ゲーム開発者のための C++11/C++14

オブジェクトのポインタはスマートポインタで管理しよう

スマートポインタは補助関数で作って、パフォーマンスの利得と、記述の一貫性を得よう

復習

Page 116: ゲーム開発者のための C++11/C++14

Transparent operator functorsを使おう

11.

Page 117: ゲーム開発者のための C++11/C++14

将来起こりそうな問題は?

vector<unsigned> v { 10, 50, 20, 30 };

sort(v.begin(),v.end(),

greater<unsigned>());

Page 118: ゲーム開発者のための C++11/C++14

将来起こりそうな問題は?

vector<unsigned> v { 10, 50, 20, 30 };

sort(v.begin(),v.end(),

greater<unsigned>());

vector<int> v { -10, 50, 20, 30 };

sort(v.begin(),v.end(),

greater<unsigned>()); // oops!

Page 119: ゲーム開発者のための C++11/C++14

Transparent operator functors

vector<unsigned> v { 10, 50, 20, 30 };

sort(v.begin(),v.end(),greater<>());

比較・算術用クラステンプレート[less, greater, plus, multiplies …] をテンプレート実引数なしで使える

Page 120: ゲーム開発者のための C++11/C++14

<functional> ヘッダの関数オブジェクトをテンプレート実引数なしで使おう

単に記述が短いだけでなく、型を変更した際のトラブルを防げる

復習

Page 121: ゲーム開発者のための C++11/C++14

古いイディオムを捨てよう

12.

Page 122: ゲーム開発者のための C++11/C++14

これまでのイディオムを新しい C++ の機能で置き換えられないか再確認しよう

C++11/14 はよりシンプルで、高速、安全な代替手段を提供しているかもしれない

要約

Page 123: ゲーム開発者のための C++11/C++14

shrink to fit

vector<int> v;

vector<int>(v).swap(v);

vector<int> v;

v.shrink_to_fit();

Page 124: ゲーム開発者のための C++11/C++14

配列の範囲

int a[] = { 5, 3, 6, 8, 2 };

const int size = sizeof(a)/sizeof(a[0]);

sort(a,a+size);

int a[] = { 5, 3, 6, 8, 2 };

sort(begin(a),end(a));

Page 125: ゲーム開発者のための C++11/C++14

Safe bool

/*

Safe bool は operator bool を定義した

オブジェクトの無意味な比較を防ぐ。実装省略

*/

struct Something {

explicit operator bool() const;

};

Page 126: ゲーム開発者のための C++11/C++14

コンパイル時 assert

#define ASSERT_CONCAT_(a, b) a##b

#define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b)

#define STATIC_ASSERT(e,m) ¥

enum{ASSERT_CONCAT(static_assert_,__COUNTER__)=1/(!!(e))}

STATIC_ASSERT(sizeof(int)==4,"xxxx");

static_assert(sizeof(int)==4,"xxxx");

Page 127: ゲーム開発者のための C++11/C++14

これまでのイディオムを新しい C++ の機能で置き換えられないか再確認しよう

C++11/14 はよりシンプルで、高速、安全な代替手段を提供しているかもしれない

復習

Page 128: ゲーム開発者のための C++11/C++14

新しいアルゴリズムを知ろう

13.

Page 129: ゲーム開発者のための C++11/C++14

<algorithm> ヘッダの新しいアルゴリズム関数を知ろう

ちょっとした操作やループを、これまでより短く、早いコードで書けるようになる

要約

Page 130: ゲーム開発者のための C++11/C++14

const int a = 5, b = 10, c = 50, d = 20;

const int smallest

= min(min(min(a,b),c),d); // 5

const int largest

= max(max(max(a,b),c),d); // 50

最小/最大値の取得3 つ以上の変数に対しては何重もの min() / max() が必要

Page 131: ゲーム開発者のための C++11/C++14

const int a = 5, b = 10, c = 50, d = 20;

const int smallest

= min({ a, b, c, d }); // 5

const int largest

= max({ a, b, c, d }); // 50

最小/最大値の取得initializer-list で複数の値を渡す

Page 132: ゲーム開発者のための C++11/C++14

int a = 25, b = 30;

const int smaller = min(a,b); // 25

const int larger = max(a,b); // 30

最小/最大値を同時に取得min() と max() で比較演算が 2 回必要

Page 133: ゲーム開発者のための C++11/C++14

int a = 25, b = 30;

// results は pair<int,int> 型

const auto results = minmax(a,b);

const int smaller = results.first; // 25

const int larger = results.second; // 30

最小/最大値を同時に取得minmax() で比較演算が 1 回に

Page 134: ゲーム開発者のための C++11/C++14

int a[100]; // {0,1,2,3,...} で初期化したい

vector<int> v(50); // {1000,1001,...}

for (int i=0; i<100; ++i)

a[i] = i;

for (size_t i=0; i<v.size(); ++i)

v[i] = i + 1000;

配列に連続した値を代入ループが必要

Page 135: ゲーム開発者のための C++11/C++14

int a[100]; // {0,1,2,3,...}

vector<int> v(50); // {1000,1001,...}

iota(begin(a),end(a),0);

iota(v.begin(),v.end(),1000);

配列に連続した値を代入iota() アルゴリズムを使おう

Page 136: ゲーム開発者のための C++11/C++14

const int maxVal = 500; // 500円まで

bool ruleKept = true;

for (size_t i=0; i<v.size(); ++i) {

if (v[i] > maxVal) {

ruleKept = false;

break;

}

}

全要素の条件チェックループが必要

Page 137: ゲーム開発者のための C++11/C++14

const int maxVal = 500;

const bool ruleKept

= all_of(v.begin(),v.end(),

[=](int n){ return n<=maxVal; });

全要素の条件チェックall_of() アルゴリズムを使おう

Page 138: ゲーム開発者のための C++11/C++14

const int maxVal = 500;

const bool ruleBroken

= any_of(v.begin(),v.end(),

[=](int n){ return n>maxVal; });

const bool ruleKept

= none_of(v.begin(),v.end(),

[=](int n){ return n>maxVal; });

全要素の条件チェック文脈に応じて any_of() ,none_of アルゴリズムも使おう

Page 139: ゲーム開発者のための C++11/C++14

vector<int> v { 1, 2, 3, 4, 5, 6, 7 };

shuffle(v.begin(), v.end(),

mt19937(random_device()()));

要素をランダムに並び替えshuffle() アルゴリズムと乱数エンジンを使おう

Page 140: ゲーム開発者のための C++11/C++14

<algorithm> ヘッダの新しいアルゴリズム関数を知ろう

ちょっとした操作やループを、これまでより短く、早いコードで書けるようになる

復習

Page 141: ゲーム開発者のための C++11/C++14

新しいライブラリを知ろう

14.

Page 142: ゲーム開発者のための C++11/C++14

新しく追加されたライブラリによって、これまで難しかった処理や高速なデータ管理が可能になる

要約

Page 143: ゲーム開発者のための C++11/C++14

const auto start = chrono::system_clock::now();

// 何らかの処理

const auto end = chrono::system_clock::now();

const chrono::duration<double> elapsed

= end - start;

cout << "経過時間: " << elapsed.count() << "秒¥n";

<chrono> [1/2]

時間の測定

Page 144: ゲーム開発者のための C++11/C++14

const chrono::minutes min(5);

const chrono::seconds sec(15);

// 型は std::chrono::seconds

const auto result = min + sec;

cout << result.count() << '¥n'; // 315

<chrono> [2/2]

時間の計算と単位の変換

Page 145: ゲーム開発者のための C++11/C++14

string s = "Hello C++11, C++14 & C++1y!";

const regex e("C¥¥+¥¥+[0-9][0-9a-z]");

smatch m;

while (regex_search(s,m,e)) {

cout << m[0] << '¥n';

s = m.suffix().str();

} // C++11 C++14 C++1y

<regex> [1/2]

正規表現にマッチする文字列の検索

Page 146: ゲーム開発者のための C++11/C++14

const string s = "C++11, C++14 and C++1y";

const regex e("¥¥d");

cout << regex_replace(s,e,"[$&]") << '¥n';

// C++[1][1], C++[1][4] and C++[1]y

<regex> [2/2]

正規表現を使った文字列の置換

Page 147: ゲーム開発者のための C++11/C++14

tuple<string,int,char> GetStudent()

{

return make_tuple("John", 86, 'B');

}

const auto student = GetStudent();

cout << get<0>(student) << '¥n'

<< get<1>(student) << '¥n'

<< get<2>(student) << '¥n';

<tuple>複数の型をまとめて 1 つの型を作る

Page 148: ゲーム開発者のための C++11/C++14

unordered_set<string> s = {

"C++", "Java", "Ruby", "PHP"

};

s.emplace("Haskell");

if (s.find("C#") == s.end())

cout << "not found¥n";

<unordered_set>O(1) で要素にアクセスできる、ハッシュを使った非順序 set

Page 149: ゲーム開発者のための C++11/C++14

unordered_map<string,int> m {

{ "C++98", 1998 },

{ "C++11", 2011 }

};

m.emplace("C++14",2014);

cout << m["C++11"] << '¥n'; // 2011

<unordered_map>O(1) で要素にアクセスできる、ハッシュを使った非順序 map

Page 150: ゲーム開発者のための C++11/C++14

新しく追加されたライブラリによって、これまで難しかった処理や高速なデータ管理が可能になる

復習

Page 151: ゲーム開発者のための C++11/C++14

今日紹介したのは、新しい C++ の一部分

Page 152: ゲーム開発者のための C++11/C++14

追加資料 1Visual C++ で使える C++11by @nekko1119 さん

http://www.slideshare.net/nekko1119/c11-in-visual-c

Page 153: ゲーム開発者のための C++11/C++14

追加資料 2C++14 Overviewby @cpp_akira さん

http://www.slideshare.net/faithandbrave/c14-overview

Page 154: ゲーム開発者のための C++11/C++14

追加資料 3

cpprefjp (日本語)http://cpprefjp.github.io/

cppreference.com (英語)http://en.cppreference.com/w/

cplusplus.com (英語)http://www.cplusplus.com/reference/

Page 155: ゲーム開発者のための C++11/C++14

Question?

1. 新しい乱数ライブラリを使おう

2. 型の宣言は auto に任せよう

3. 範囲ベースのループを使おう

4. ラムダ式を使おう

5. Emplacement の使い所を知ろう

6. 強く型付けされた enum を使おう

7. array を活用しよう

8. NULL を nullptr に置き換えよう

9. 右辺値参照を理解しよう

10. スマートポインタは補助関数で作ろう

11. Transparent operator functors を使おう

12. 古いイディオムを捨てよう

13. 新しいアルゴリズムを知ろう

14. 新しいライブラリを知ろう

Page 156: ゲーム開発者のための C++11/C++14

2013.9.14

Ryo Suzuki@Reputeless

[email protected]

最新のC++で設計されたゲームとメディアアートのためのC++ライブラリ Siv3D

http://play-siv3d.hateblo.jp/

Page 157: ゲーム開発者のための C++11/C++14

更新履歴

2015.1.11 v1.03

p.58 関数名の誤植を修正

p.154 cpprefjp の URL を更新

2013.9.28 v1.02

p.26 コンパイルエラーになるコードを修正

2013.9.17 v1.01

p.42 変数に const をつけていた誤植を修正

p.63 ) が 1 つ多かった誤植を修正