c++11 (他) 入門
DESCRIPTION
TRANSCRIPT
C++11 (他) 入門 ~ Java, C, +αを学んだ貴方へ(というのは真っ赤な嘘)
Yuta Hirokawa, @krustf/総長
2012/2/15 1
内容, 注意
2012/2/15 2
Effective C++ の重要そうな部分を独断で抜き出し
C++11 の規格で直結しそうな機能を幾つか紹介
テンプレートに関するテクニックを少々解説
最新規格 C++11(旧称C++0x) に則る
ウェブページや書籍では未だC++0x表記による情報が多い
検索時は気を付けること
導入
注意
2012/2/15 3
C++11 完全対応コンパイラは未だ無い
2012年2月14日現在
当スライドでは以下の環境を使用する
一部以下の環境では使えないコードがある(かも)
Compiler gcc 4.5
Build Option -std=gnu++0x
Service ideone.com
導入
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の開発者ブログが炎上しました
導入
選りすぐり Effective C++ 10の項目
ここはさらさらやります
2012/2/15 5
1. #define よりも const, enum, inline !
2012/2/15 6
define は文字列の置換であり型情報が無い
文字列置換によるマジック(関数や変数の自動生成等)
でない限りインライン関数の方が良い
strongly typed enum(C++11)により強い型安全なenumを使用する事が可能
Effective C++ から
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++ から
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++ から
2. 可能な限り const を使う
2012/2/15 9
「変更不可」を明示しコンパイラにその制約を守るための
手助けを要請するもの
本来書き変えない部分における書き変えを防ぎ
コンパイル時にバグを未然防止する
クラスにおいて読み取り専用のメンバ関数には必ず
const を付ける(const メンバ関数)
Effective C++ から
const メンバ関数
2012/2/15 10
そのメンバ関数内でのクラスのインスタンス変数を一切変更できなくする
「論理的な不変性」(関わるデータ全ての変更禁止)
「ビットレベルでの不変性」(データメンバの変更禁止)
struct hoge {
double x;
double get_x() const {
// x *= 2; error!!
return x;
}
};
Effective C++ から
3. constructorとdestructorを使う
2012/2/15 11
ctor と dtor は C++ のクラスが自動生成を行う
自動生成されたものは default ctor/dtor と呼ばれる
自動生成ではなく独自に引数を指定して作成可能
但し、その場合default ctor/dtor は自動生成されない
自動生成して欲しくない関数は delete する
default and deleted function
Effective C++ から
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++ から
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++ から
4. 仮想デストラクタを無暗に付けない
2012/2/15 14
動的ポリモルフィズムの場合, デストラクタに virtual を
付けて仮想デストラクタにする必要がある
しかし, 無暗に全てのクラスのデストラクタにつけることは
パフォーマンス低下や作者の意図していない継承となり
バグの発生につながる
Effective C++ から
5. デストラクタから例外を絶対に投げない
2012/2/15 15
アクティブ(発生している)な例外が複数あると
undefined-behavior(未定義動作)となる
デストラクタから例外を投げる設計では, アクティブな
例外が複数個発生しやすい
デストラクタで例外を補足した場合はデストラクタ内で
適切な処理をする必要がある
abort で強制終了
デストラクタで握りつぶす(飲み込む)
Effective C++ から
6. ctor と dtor では仮想関数を呼ばない
2012/2/15 16
基底クラスが, 派生クラスによってオーバーライドされた
仮想関数を呼び出す場合, ctor 内では派生クラスの
データメンバの初期化を終了していない
初期化されていない値を使用してしまう!
初期化順番:基底クラスから派生クラス
破棄の順番:派生クラスから基底クラス
Effective C++ から
7. リソース管理は RAII を使う
2012/2/15 17
RAII (Resource Acquisition Is Initialization)
「リソースの確保が初期化」
リソースの確保と管理クラスの初期化は同タイミング
コンストラクタでリソースを確保、管理クラスの初期化
デストラクタで自動的に削除
Effective C++ から
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++ から
std::shared_ptr, std::unique_ptr
2012/2/15 19
C++11 で追加された RAII によるリソース管理クラス
基本的には new で確保された動的領域の管理
shared_ptr は色々な関数で使う共有オブジェクト用
unique_ptr はクラス内部のみなど固有オブジェクト用
shared_ptr atomic access などもある(説明省略)
Effective C++ から
8. 値渡しより const 参照渡しを使う
2012/2/15 20
値渡し(コピー)では大きなサイズの配列のコピー操作に
時間がかかってしまい無駄が大きい
const 参照によってコピーを防ぎ, さらに意図しない改竄
を防ぐことができる
copy ctor が禁止されているクラスでも使える
const 参照では, const メンバ関数のみが使用可能
Effective C++ から
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++ から
9.C++スタイルキャストを使う
2012/2/15 22
static_cast
明示的な型変換を行う
reinterpret_cast
低レベルキャスト(ポインタ間変換等)を行う
dynamic_cast
安全なダウンキャストを行う(基底クラスから派生クラスへ)
実行コストが高い
const_cast
const を取り外す際に使われる, 付加も可能
但し, 外した後のデータを変更した場合の動作は未定義
Effective C++ から
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++ から
10. 継承よりコンポジションを先に考える
2012/2/15 24
継承はクラスの公開メンバを増やしてしまう
クラスの使用者にとって不要なものも増える
クラスのコンポジション(合成)によって, 必要な機能のみ
を組み合わせて公開メンバとすることで外部への情報を
すっきりさせる
Effective C++ から
C++11 の必要そうな機能
途中に説明したものに加えて
2012/2/15 25
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
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
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
4. decltype
2012/2/15 29
sizeof の型推論版
ある計算によって戻ってきた型を調べる
int i = 42;
double pi = 3.141592;
decltype(i); // int
decltype(i + pi); // double
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
6. Lambda expressions
2012/2/15 31
ラムダ式
匿名の関数オブジェクトを生成
関数オブジェクトや関数を作る手間がある程度省ける
外のスコープの変数を参照も可能
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
追加機能は非常に多い
2012/2/15 33
コア言語サポートだけではない
導入された新たなクラスや関数の一部
shared_ptr インスタンスの共有
unique_ptr インスタンスの所有
unordered ハッシュマップ
thread 標準スレッドライブラリ
random メルセンヌツイスタ等の乱数生成
C++11
テンプレートの美味しい調理法
しっかりサンプルコードがあります
2012/2/15 34
静的ポリモルフィズム
2012/2/15 35
動的ポリモルフィズムは「実行時」に動作内容を決める
「コンパイル時」に動作内容を決めるのが
静的ポリモルフィズムと言える
テンプレートを用い, 様々な方向で静的ポリモルフィズムを実現できる
テンプレートテクニック
1. Tag Dispatch
2012/2/15 36
型に応じて適切な関数を呼び分ける
外部公開する関数は1つだが, 内部では型に応じて
複数の関数を呼び分けるのが一般的
その型は Tag として空のクラスで定義する
テンプレートテクニック
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; };
};
テンプレートテクニック
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."
テンプレートテクニック
1. Tag Dispatch
2012/2/15 39
前述の方法では, call_tag がないとビルドエラーになる
tag が無い場合に汎用的な処理をしたい時がある
Traits を使って tag の取り出しを問い合わせる
call(int()); // not typedef call_tag
// エラーにせず汎用処理がしたい
テンプレートテクニック
2. Traits
2012/2/15 40
ある型 T に対する情報をコンパイル時に問い合わせる
STL では iterator_traits などが有名
テンプレートの特殊化によって
ある型に対する情報を個別に設定する
テンプレートテクニック
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;
};
テンプレートテクニック
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; };
};
テンプレートテクニック
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
テンプレートテクニック
余談: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
テンプレートテクニック
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
テンプレートテクニック
3. TMP - Template Meta Programming
2012/2/15 46
イメージとしてプログラムを生成するためのコード
様々なメタ関数を駆使することで実現
テンプレートのインスタンス化を利用して
様々な計算をコンパイル時に行う
先ほどの factorial もメタ関数
テンプレートテクニック
3. TMP - Template Meta Programming
2012/2/15 47
メタ関数は
再帰でループを表現
特殊化で条件分岐
factorial メタ関数は
再帰でループ計算
特殊化で 0 の際は 1 を返すようにする
ヘルパを駆使するのが一般的
Boost.MPL が素晴らしい
テンプレートテクニック
4. Type Erasure
2012/2/15 48
C++ の超静的型処理は迷惑
テンプレートでは動的な型処理が困難
型情報を消し, 動的型処理の手助けを行う
非テンプレート基本クラスとテンプレート派生クラス
2つを用いて型情報を消すのが一般的
例として, あるメンバ関数を型に寄らず呼び出してみる
テンプレートテクニック
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(); };
テンプレートテクニック
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;
};
テンプレートテクニック
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
テンプレートテクニック
5. SFINAE
2012/2/15 52
Substitution Failure Is Not An Error
置き換え失敗はエラーではない
テンプレートの置き換えに失敗した場合
その関数等を呼び出し候補から外す
関数テンプレートのオーバーロード解決を補佐する
機能として重宝されることが多い
コードが分かりづらくなりやすい
テンプレートテクニック
5. SFINAE
2012/2/15 53
Boost.MPL やメタ関数を使い倒す
疲れたので, ideone にのみ掲載
サンプルでは, 配列かそうでないかで出力を切替
http://ideone.com/1JpTD
テンプレートテクニック
参考文献
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/
参考文献
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