c++11 (他) 入門

55
C++11 () 入門 Java, C, +αを学んだ貴方へ(というのは真っ赤な嘘) Yuta Hirokawa, @krustf/総長 2012/2/15 1

Upload: y-hirokawa

Post on 22-Apr-2015

14.302 views

Category:

Technology


2 download

DESCRIPTION

 

TRANSCRIPT

Page 1: C++11 (他) 入門

C++11 (他) 入門 ~ Java, C, +αを学んだ貴方へ(というのは真っ赤な嘘)

Yuta Hirokawa, @krustf/総長

2012/2/15 1

Page 2: C++11 (他) 入門

内容, 注意

2012/2/15 2

Effective C++ の重要そうな部分を独断で抜き出し

C++11 の規格で直結しそうな機能を幾つか紹介

テンプレートに関するテクニックを少々解説

最新規格 C++11(旧称C++0x) に則る

ウェブページや書籍では未だC++0x表記による情報が多い

検索時は気を付けること

導入

Page 3: C++11 (他) 入門

注意

2012/2/15 3

C++11 完全対応コンパイラは未だ無い

2012年2月14日現在

当スライドでは以下の環境を使用する

一部以下の環境では使えないコードがある(かも)

Compiler gcc 4.5

Build Option -std=gnu++0x

Service ideone.com

導入

Page 4: C++11 (他) 入門

C++11 機能の対応表

2012/2/15 4

http://wiki.apache.org/stdcxx/C++0xCompilerSupport

last edited 2012-02-13

GCC や Clang がC++11の対応状況が良い

MSVC はお粗末なので止めて下さい(切実)

海外のページでMSVC10か11の悲惨な対応状況によって

MSの開発者ブログが炎上しました

導入

Page 5: C++11 (他) 入門

選りすぐり Effective C++ 10の項目

ここはさらさらやります

2012/2/15 5

Page 6: C++11 (他) 入門

1. #define よりも const, enum, inline !

2012/2/15 6

define は文字列の置換であり型情報が無い

文字列置換によるマジック(関数や変数の自動生成等)

でない限りインライン関数の方が良い

strongly typed enum(C++11)により強い型安全なenumを使用する事が可能

Effective C++ から

Page 7: C++11 (他) 入門

1. #define よりも const, enum, inline !

2012/2/15 7

// #define PI 3.14...

const double PI = 3.14159265358979;

// #define pow2(x) x * x

inline

template<class T>

T pow2(T const& v) { return v * v; }

Effective C++ から

Page 8: C++11 (他) 入門

strongly typed enum

2012/2/15 8

直訳 「強い型付けの列挙子」

これまでと違いenum名をスコープとして列挙子名を指定

列挙子の型を指定できるように(従来はint型)

enum class Color : std::uint32_t {

Red, Green, Blue, White, Black, Yellow

};

Color c = Color::Green;

// Color c = White; error!!

Effective C++ から

Page 9: C++11 (他) 入門

2. 可能な限り const を使う

2012/2/15 9

「変更不可」を明示しコンパイラにその制約を守るための

手助けを要請するもの

本来書き変えない部分における書き変えを防ぎ

コンパイル時にバグを未然防止する

クラスにおいて読み取り専用のメンバ関数には必ず

const を付ける(const メンバ関数)

Effective C++ から

Page 10: C++11 (他) 入門

const メンバ関数

2012/2/15 10

そのメンバ関数内でのクラスのインスタンス変数を一切変更できなくする

「論理的な不変性」(関わるデータ全ての変更禁止)

「ビットレベルでの不変性」(データメンバの変更禁止)

struct hoge {

double x;

double get_x() const {

// x *= 2; error!!

return x;

}

};

Effective C++ から

Page 11: C++11 (他) 入門

3. constructorとdestructorを使う

2012/2/15 11

ctor と dtor は C++ のクラスが自動生成を行う

自動生成されたものは default ctor/dtor と呼ばれる

自動生成ではなく独自に引数を指定して作成可能

但し、その場合default ctor/dtor は自動生成されない

自動生成して欲しくない関数は delete する

default and deleted function

Effective C++ から

Page 12: C++11 (他) 入門

3. constructor と destructor を使う

2012/2/15 12

class complex {

public:

complex() : r(), i() {};

complex(double _r, double _i)

: r(_r), i(_i) {};

private:

double r, i;

};

Effective C++ から

Page 13: C++11 (他) 入門

default and deleted function

2012/2/15 13

自動生成してほしいものを default

生成禁止してほしいものを delete

class hoge {

hoge() = default;

hoge(hoge const&) = delete; // copy の禁止

hoge& operator=(hoge const&) = delete;

};

hoge h;

// h = hoge(); Error!!

Effective C++ から

Page 14: C++11 (他) 入門

4. 仮想デストラクタを無暗に付けない

2012/2/15 14

動的ポリモルフィズムの場合, デストラクタに virtual を

付けて仮想デストラクタにする必要がある

しかし, 無暗に全てのクラスのデストラクタにつけることは

パフォーマンス低下や作者の意図していない継承となり

バグの発生につながる

Effective C++ から

Page 15: C++11 (他) 入門

5. デストラクタから例外を絶対に投げない

2012/2/15 15

アクティブ(発生している)な例外が複数あると

undefined-behavior(未定義動作)となる

デストラクタから例外を投げる設計では, アクティブな

例外が複数個発生しやすい

デストラクタで例外を補足した場合はデストラクタ内で

適切な処理をする必要がある

abort で強制終了

デストラクタで握りつぶす(飲み込む)

Effective C++ から

Page 16: C++11 (他) 入門

6. ctor と dtor では仮想関数を呼ばない

2012/2/15 16

基底クラスが, 派生クラスによってオーバーライドされた

仮想関数を呼び出す場合, ctor 内では派生クラスの

データメンバの初期化を終了していない

初期化されていない値を使用してしまう!

初期化順番:基底クラスから派生クラス

破棄の順番:派生クラスから基底クラス

Effective C++ から

Page 17: C++11 (他) 入門

7. リソース管理は RAII を使う

2012/2/15 17

RAII (Resource Acquisition Is Initialization)

「リソースの確保が初期化」

リソースの確保と管理クラスの初期化は同タイミング

コンストラクタでリソースを確保、管理クラスの初期化

デストラクタで自動的に削除

Effective C++ から

Page 18: C++11 (他) 入門

7. リソース管理は RAII を使う

2012/2/15 18

struct File {

std::FILE* fp;

explicit File(std::FILE* _fp) : fp(_fp) {};

~File() { if(fp) std::fclose(fp); };

};

void save_file(std::string const& path) {

File file(std::fopen(path.c_str(), "w"));

std::fwrite(...);

...

} // auto file close.

Effective C++ から

Page 19: C++11 (他) 入門

std::shared_ptr, std::unique_ptr

2012/2/15 19

C++11 で追加された RAII によるリソース管理クラス

基本的には new で確保された動的領域の管理

shared_ptr は色々な関数で使う共有オブジェクト用

unique_ptr はクラス内部のみなど固有オブジェクト用

shared_ptr atomic access などもある(説明省略)

Effective C++ から

Page 20: C++11 (他) 入門

8. 値渡しより const 参照渡しを使う

2012/2/15 20

値渡し(コピー)では大きなサイズの配列のコピー操作に

時間がかかってしまい無駄が大きい

const 参照によってコピーを防ぎ, さらに意図しない改竄

を防ぐことができる

copy ctor が禁止されているクラスでも使える

const 参照では, const メンバ関数のみが使用可能

Effective C++ から

Page 21: C++11 (他) 入門

8. 値渡しより const 参照渡しを使う

2012/2/15 21

template<class T>

void func(std::vector<T> const& v) {

// v.push_back(42); error!!

std::cout << v[0] << std::endl;

// v[0] = 2; error!!

}

Effective C++ から

Page 22: C++11 (他) 入門

9.C++スタイルキャストを使う

2012/2/15 22

static_cast

明示的な型変換を行う

reinterpret_cast

低レベルキャスト(ポインタ間変換等)を行う

dynamic_cast

安全なダウンキャストを行う(基底クラスから派生クラスへ)

実行コストが高い

const_cast

const を取り外す際に使われる, 付加も可能

但し, 外した後のデータを変更した場合の動作は未定義

Effective C++ から

Page 23: C++11 (他) 入門

9.C++スタイルキャストを使う

2012/2/15 23

std::uint32_t i = 42;

std::int32_t j = static_cast<std::int32_t>(i);

void* ptr = get_ptr();

char* cptr = reinterpret_cast<char*>(ptr);

const char* s = "hello, world";

char* ss = const_cast<char*>(s);

Effective C++ から

Page 24: C++11 (他) 入門

10. 継承よりコンポジションを先に考える

2012/2/15 24

継承はクラスの公開メンバを増やしてしまう

クラスの使用者にとって不要なものも増える

クラスのコンポジション(合成)によって, 必要な機能のみ

を組み合わせて公開メンバとすることで外部への情報を

すっきりさせる

Effective C++ から

Page 25: C++11 (他) 入門

C++11 の必要そうな機能

途中に説明したものに加えて

2012/2/15 25

Page 26: C++11 (他) 入門

1. Angle bracket

2012/2/15 26

従来テンプレート内にテンプレートが入る場合

連続した山かっこが operator>> などに勘違いされた

コンパイラに勘違いされないようになった

// C++03

std::vector<std::vector<int> > v;

// C++11

std::vector<std::vector<int>> v

C++11

Page 27: C++11 (他) 入門

2. Initializer list

2012/2/15 27

ユーザ定義クラスで配列のような

初期化構文を提供可能に

STL クラスも対応

std::vector<int> v = { 1, 2, 3 };

v[0] == 1;

v[1] == 2;

v[2] == 3;

C++11

Page 28: C++11 (他) 入門

3. auto

2012/2/15 28

戻り値による型推論

これにより, C++03 時代での auto との互換性が削除

関数テンプレート内でのローカル変数などに使う

コンパイラが知る情報に任せて面倒な型名を省略

std::vector<int> v;

auto b = v.begin(); // is vector<int>::iterator

auto e = v.end(); // is vector<int>::iterator

C++11

Page 29: C++11 (他) 入門

4. decltype

2012/2/15 29

sizeof の型推論版

ある計算によって戻ってきた型を調べる

int i = 42;

double pi = 3.141592;

decltype(i); // int

decltype(i + pi); // double

C++11

Page 30: C++11 (他) 入門

5. Range-based for

2012/2/15 30

他言語にはよくある foreach 構文

std::vector<int> v = { 1, 2, 3, 4, 5 };

for(auto& i : v) {

i *= 2;

}

for(auto i : v) {

std::cout << i << std::endl;

}

C++11

Page 31: C++11 (他) 入門

6. Lambda expressions

2012/2/15 31

ラムダ式

匿名の関数オブジェクトを生成

関数オブジェクトや関数を作る手間がある程度省ける

外のスコープの変数を参照も可能

C++11

Page 32: C++11 (他) 入門

6. Lambda expressions

2012/2/15 32

auto f = [](int i) -> int { return i * i; };

int result = f(2); // result == 4;

std::vector<int> v = { 1, 2, 3, 4, 5 };

int sum = 0;

std::for_each( v.begin(), v.end()

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

// sum == 15

C++11

Page 33: C++11 (他) 入門

追加機能は非常に多い

2012/2/15 33

コア言語サポートだけではない

導入された新たなクラスや関数の一部

shared_ptr インスタンスの共有

unique_ptr インスタンスの所有

unordered ハッシュマップ

thread 標準スレッドライブラリ

random メルセンヌツイスタ等の乱数生成

C++11

Page 34: C++11 (他) 入門

テンプレートの美味しい調理法

しっかりサンプルコードがあります

2012/2/15 34

Page 35: C++11 (他) 入門

静的ポリモルフィズム

2012/2/15 35

動的ポリモルフィズムは「実行時」に動作内容を決める

「コンパイル時」に動作内容を決めるのが

静的ポリモルフィズムと言える

テンプレートを用い, 様々な方向で静的ポリモルフィズムを実現できる

テンプレートテクニック

Page 36: C++11 (他) 入門

1. Tag Dispatch

2012/2/15 36

型に応じて適切な関数を呼び分ける

外部公開する関数は1つだが, 内部では型に応じて

複数の関数を呼び分けるのが一般的

その型は Tag として空のクラスで定義する

テンプレートテクニック

Page 37: C++11 (他) 入門

1. Tag Dispatch

2012/2/15 37

struct hoge_tag {};

struct foo_tag {};

struct hoge { typedef hoge_tag call_tag; };

struct foo { typedef foo_tag call_tag; };

namespace detail {

void call_(hoge_tag) { std::cout << "hoge." << std::endl; };

void call_(foo_tag) { std::cout << "foo." << std::endl; };

};

テンプレートテクニック

Page 38: C++11 (他) 入門

1. Tag Dispatch

2012/2/15 38

template<class T>

void call(T) {

typedef typename T::call_tag call_tag;

detail::call_(call_tag());

}

call(hoge()); // "hoge."

call(foo()); // "foo."

テンプレートテクニック

Page 39: C++11 (他) 入門

1. Tag Dispatch

2012/2/15 39

前述の方法では, call_tag がないとビルドエラーになる

tag が無い場合に汎用的な処理をしたい時がある

Traits を使って tag の取り出しを問い合わせる

call(int()); // not typedef call_tag

// エラーにせず汎用処理がしたい

テンプレートテクニック

Page 40: C++11 (他) 入門

2. Traits

2012/2/15 40

ある型 T に対する情報をコンパイル時に問い合わせる

STL では iterator_traits などが有名

テンプレートの特殊化によって

ある型に対する情報を個別に設定する

テンプレートテクニック

Page 41: C++11 (他) 入門

2. Traits

2012/2/15 41

template<class T> struct call_traits {

typedef T call_tag;

};

template<> struct call_traits<hoge> {

typedef hoge::call_tag call_tag;

};

template<> struct call_traits<foo> {

typedef foo::call_tag call_tag;

};

テンプレートテクニック

Page 42: C++11 (他) 入門

2. Traits

2012/2/15 42

namespace detail {

void call_(hoge_tag) { ... };

void call_(foo_tag) { ... };

template<class T>

void call_(T) { std::cout << "other." << std::endl; };

};

テンプレートテクニック

Page 43: C++11 (他) 入門

2. Traits

2012/2/15 43

template<class T>

void call(T) {

typedef typename call_traits<T>::call_tag call_tag;

detail::call_(call_tag());

}

call(hoge()); // "hoge."

call(foo()); // "foo."

call(int()); // "other."

- http://ideone.com/3vmIv

テンプレートテクニック

Page 44: C++11 (他) 入門

余談:MPI の MPI_Datatype を型から取得

2012/2/15 44

template<class T> struct mpi_data_type {};

template<> struct mpi_data_type<float> {

static MPI_Datatype apply() { return MPI_FLOAT; }

};

template<> struct mpi_data_type<double> {

static MPI_Datatype apply() { return MPI_DOUBLE; }

};

mpi_data_type<float>::apply(); // MPI_FLOAT

mpi_data_type<double>::apply(); // MPI_DOUBLE

テンプレートテクニック

Page 45: C++11 (他) 入門

2.7182. 階乗を静的に求める

2012/2/15 45

template<int N>

struct factorial {

static const int value = factorial<N-1>::value * N;

};

template<>

struct factorial<0> {

static const int value = 1;

};

std::size_t result = factorial<5>::value; // 120

- http://ideone.com/R8ZFz

テンプレートテクニック

Page 46: C++11 (他) 入門

3. TMP - Template Meta Programming

2012/2/15 46

イメージとしてプログラムを生成するためのコード

様々なメタ関数を駆使することで実現

テンプレートのインスタンス化を利用して

様々な計算をコンパイル時に行う

先ほどの factorial もメタ関数

テンプレートテクニック

Page 47: C++11 (他) 入門

3. TMP - Template Meta Programming

2012/2/15 47

メタ関数は

再帰でループを表現

特殊化で条件分岐

factorial メタ関数は

再帰でループ計算

特殊化で 0 の際は 1 を返すようにする

ヘルパを駆使するのが一般的

Boost.MPL が素晴らしい

テンプレートテクニック

Page 48: C++11 (他) 入門

4. Type Erasure

2012/2/15 48

C++ の超静的型処理は迷惑

テンプレートでは動的な型処理が困難

型情報を消し, 動的型処理の手助けを行う

非テンプレート基本クラスとテンプレート派生クラス

2つを用いて型情報を消すのが一般的

例として, あるメンバ関数を型に寄らず呼び出してみる

テンプレートテクニック

Page 49: C++11 (他) 入門

4. Type Erasure

2012/2/15 49

struct any {

template<class T> any(T const& i) : _erasure() {

_erasure = new derive<T>(i);

}

any() = default;

template<class T> any& operator=(T const& i) {

if(_erasure) { delete _erasure; };

_erasure = new derive<T>(i);

}

void call() const { _erasure->call(); };

テンプレートテクニック

Page 50: C++11 (他) 入門

4. Type Erasure

2012/2/15 50

private:

struct base {

virtual ~base() {};

virtual void call() = 0;

};

template<class U> struct derive : public base {

U val;

derive(U const& i) : val(i) {};

void call() { val.call(); };

};

base* _erasure;

};

テンプレートテクニック

Page 51: C++11 (他) 入門

4. Type Erasure

2012/2/15 51

struct hoge {

void call() const { std::cout << "hoge::call" << std::endl; };

};

struct foo {

void call() const { std::cout << "foo::call" << std::endl; };

};

any val;

val = hoge();

val.call(); // "hoge::call"

val = foo();

val.call(); // "foo::call"

- http://ideone.com/3Z8Lr

テンプレートテクニック

Page 52: C++11 (他) 入門

5. SFINAE

2012/2/15 52

Substitution Failure Is Not An Error

置き換え失敗はエラーではない

テンプレートの置き換えに失敗した場合

その関数等を呼び出し候補から外す

関数テンプレートのオーバーロード解決を補佐する

機能として重宝されることが多い

コードが分かりづらくなりやすい

テンプレートテクニック

Page 53: C++11 (他) 入門

5. SFINAE

2012/2/15 53

Boost.MPL やメタ関数を使い倒す

疲れたので, ideone にのみ掲載

サンプルでは, 配列かそうでないかで出力を切替

http://ideone.com/1JpTD

テンプレートテクニック

Page 54: C++11 (他) 入門

参考文献

2012/2/15 54

Effective C++ 第3版, スコットメイヤーズ, 2006/05,

ピアソンエデュケーション

C++ テンプレートテクニック, επιστημη 高橋晶,

2009/04, ソフトバンククリエイティブ

C++11 Working Draft N3337, 2012/01/16

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/

Page 55: C++11 (他) 入門

参考文献

2012/2/15 55

本の虫

- http://cpplover.blogspot.com/

Faith and Brave - C++ で遊ぼう

- http://d.hatena.ne.jp/faith_and_brave/

cpprefjp

- https://sites.google.com/site/cpprefjp/

C++11 Advent Calender 2011

- http://atnd.org/events/21936