Upgrade to Pro — share decks privately, control downloads, hide ads and more …

C++11 メモ

C++11 メモ

自分用ですが、分かる人にはそれなりにわかるかもしれないメモ。

ymmt2005

May 30, 2013
Tweet

More Decks by ymmt2005

Other Decks in Programming

Transcript

  1. C++11 メモ concurrency 周りを中心に、てきとーに使えそうなところをメモ References GCC 準拠状況 Build & install

    Better types move noexcept string to/from integer chrono lambda Capturing this std::fucntion auto Uniform Initialization std::system_error std::array using Minimal GC support Concurrency まわり deadlock しないようにロックとるとか detach signal mask とか sleep CPU 個数 CPU affinity Atomic types fence memory order semantics volatile CAS References C++11: A cheat sheet C++ reference C++11 FAQ Bjarne Stroustrup 本人の FAQ。 GCC 準拠状況 GCC 4.8.1 でほぼコンプリート。でも libstdc++ には多々未実装がある。 C++11 Support in GCC libstdc++ Implementation Status Build & install 自分でビルドした。 g++ steady_clock::is_steady == false?
  2. $ sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev g++ $ tar

    xjf gcc-4.8.0.tar.bz2 $ cd gcc-4.8.0 $ mkdir build $ cd build $ ../configure --prefix=/usr/local/gcc --disable-shared --disable-multilib \ --enable-threads --enable-__cxa_atexit --enable-languages=c,c++ \ --disable-nls --enable-libstdcxx-time=rt $ make -j 4 BOOT_CFLAGS=-O2 bootstrap $ make install $ make clean PATH に を入れて、 に以下を追加。 /usr/local/gcc/bin /etc/manpath.config MANPATH_MAP /usr/local/gcc/bin /usr/local/gcc/share/man Better types int32_t とか C++11 でも使えるようになった。 http://en.cppreference.com/w/cpp/types/integer その他、型安全な enum や nullptr や Better types in C++11 tuple/tie も便利 http://en.cppreference.com/w/cpp/utility/tuple move named return value optimization 勝手にやる。move constructor があれば。 関数呼び出し等では名前がついているときは しないといけない。 std::move() 自分で move constructor を定義するときは、例外を投げないようにするべき。絶対。 Move constructors To make strong exception guarantee possible, user-defined move constructors should not throw exceptions. In fact, standard containers typically rely on std::move_if_noexcept to choose between move and copy when container elements need to be relocated. Rvalue References and Exception Safety std::unique_ptr や 等 move をサポートしているオブジェクトの所有権をどう渡すかはこの記事が良くまとめている。 std::thread If you mean for a function to claim ownership of a unique_ptr, take it by value. If you mean for a function to simply use the unique_ptr for the duration of that function's execution, take it by const&. Alternatively, pass a & or const& to the actual type pointed to, rather than using a unique_ptr. If a function may or may not claim ownership (depending on internal code paths), then take it by &&. But I strongly advise against doing this whenever possible. How do I pass a unique_ptr argument to a constructor or a function? 短く言うと、引数も返り値も値渡しで書けばいい。
  3. void f() { ... } std::thread create_thread() { return std::thread(f);

    } void g(std::thread t) { ... t.join(); } int main() { std::thread t = create_thread(); g( std::move(t) ); // forget about t return 0; } noexcept 役立たずの 指定の代わりに、 が指定できるようになった。 throw noexcept コンパイル時に例外を投げないことを保証するわけではないが、コンパイラは例外を投げないこと前提としたコードを生成する。 また、仕様の記述としての意味もあり、たとえば は resize 時に move コンストラクタが noexcept で std::vector あるなら move し、そうでないならコピーする。move コンストラクタに noexcept を指定するのは、有用だろう。 noexcept specifier noexcept operator move_if_noexcept string to/from integer std::stoi 文字列を数値に。もちろん不正なら例外飛ぶ。 std::to_string 数値を文字列に。 chrono libstdc++ の実装では、 は の alias。 high_resolution_clock system_clock 使い方:gist lambda クロージャーも作れるよ、もちろん。キモイけど。 http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B Capturing this The capture of this is special. It can only be captured by value, not by reference. this can only be captured if the closest enclosing function is a non-static member function. The lambda will have the same access as the member that created it, in terms of protected/private members. If this is captured, either explicitly or implicitly, then the scope of the enclosed class members is also tested. Accessing members of this does not require explicit use of this-> syntax.
  4. struct A { void foo() { std::cout << "Hello" <<

    std::endl; } void bar() { [this]() { foo(); } (); } }; int main() { A a; a.bar(); return 0; } std::fucntion 関数ポインタ以外のラムダ関数なんかもうまく取り扱えるようにするもの。 http://en.cppreference.com/w/cpp/utility/functional/function auto iterator とか future とか promise とか、返り値系の型は auto で済ます。 void f() { auto p = make_shared<T>(arg...); auto f = std::async(...); } Uniform Initialization {} で初期化できる文法。infamous なデフォルトコンストラクタ問題とかが解決。 struct A { A() { std::cout << "Hello" << std::endl; } }; void f() { A a(); // A a; // A a{}; // uniform initialization } でも コンストラクタを優先するので、調子に乗ってると痛い目にあう。 initializer_list std::vector v(5); // five elements, i.e. {0, 0, 0, 0, 0}. std::vector v{5}; // just a element, namely, {5}. std::system_error errno をラッピングしてくれる便利な人。それだけじゃないけど、まあ。 System error support in C++0x - part 1 http://en.cppreference.com/w/cpp/error/system_error system_category は OS が返すエラーのカテゴリ、つまり 処理用。 errno
  5. は(errnoを元にした)一般的なエラーとのことだが、これを使うなら自分用のカテゴリ作る方がいい気がする。 generic_category std::array いらない子らしい。 http://stackoverflow.com/a/6113104/1493661 従来の C 配列も C++11 の

    , でイテレートできるようになったし、 begin end 要素数を数えてくれないだけ不便だとのこと。 range-based for loop もできるし。 http://en.wikipedia.org/wiki/C%2B%2B11#Range-based_for-loop using typedef の代わりに使える。partial な型も定義できる。 using int32_t = int; template<int U, int V> typename T; template<int V> using MyT = T<32, V>; Minimal GC support http://www.stroustrup.com/C++11FAQ.html#gc-abi 結論:そんなものはなかった。 Concurrency まわり Boost thread や C++11 の規格作った人が書いた本とチュートリアル。 C++ Concurrency in Action C++11 Concurrency Tutorial Future が composite できないじゃんか!って批判 Broken promisesC++0x futures 実際問題、future なんて軟弱な abstraction は C++ っぽくない。高級なお手軽さなら Go に任せておけ。 C++0x時代の Double-Checked Locking 結論: static 使え。 Hoge& getInstance() { static Hoge hoge; return hoge; } C++11標準ライブラリのスレッド安全性 とかは安心して使っていいよと。ほかは変更しない(=const method)限りいい。 std::shared_ptr deadlock しないようにロックとるとか http://en.cppreference.com/w/cpp/thread/lock_tag_t サンプルコード参照。 detach detach したスレッドは main スレッドが終わったらプロセスごと消えちゃう。
  6. Linux では。C++11 の仕様? signal mask とか 自分でやれと。従来通り、main 直後に でブロックするのが良さそうだ。 pthread_sigmask

    sleep std::this_thread::sleep_for(std::chrono::milliseconds(100)); CPU 個数 std::thread::hardware_concurrency() で取れるはずだが、gcc 4.6 では return 0 になってる。。 従来通り int get_cpucount() { return (int)sysconf(_SC_NPROCESSORS_ONLN); } とするのが無難。 CPU affinity そういうのは native でないと無理。 #include <sched.h> #include <thread> void f() { std::thread t(...); auto pt = t.native_handle(); // pthread_t cpu_set_t cs; CPU_ZERO(&cs); CPU_SET(1, &cs); sched_setaffinity(gettid(), sizeof(cs), &cs); // native handle :) } Atomic types スタックに確保した atomic 変数は 0 初期化されないので、明示的にやる。 int f() { std::atomic<int> a{0}; std::atomic<int> b = ATOMIC_VAR_INIT(0); return a += 3; } ATOMIC_VAR_INIT は C との互換性のためのものなので、普通は前者でいい。 fence std::atomic_signal_fence はコンパイラのリオーダーを抑止する。 は CPU のリオーダーを抑止する。 std::atomic_thread_fence memory order semantics http://en.cppreference.com/w/cpp/atomic/memory_order
  7. Order 解釈 memory_order_relaxed コンパイラ・CPUが自由にリオーダーできる memory_order_consume load した atomic 変数に依存する命令のリオーダーを抑止する。コンパイラのリオーダーが対象。 memory_order_acquire

    いわゆるひとつの lfence。コンパイラのリオーダーにも効く。 memory_order_release いわゆるひとつの sfence。x86 だと LOCK 命令の場合 sfence 入らない。 memory_order_acq_rel CAS 等 read-modify-write 操作のためにある。 memory_order_seq_cst いわゆるひとつの mfence。 momory_order_consume の依存関係の終了は で指示する。 kill_dependency 実際には、以下4つの順序関係に大別される。 sequential atomic 変数の操作が全部 であるなら、全スレッド間で一意な順序関係が保証される seq_cst release-acquire release したスレッドと acquire したスレッドの間で順序を保証する。 release-consume 構造体のポインタを atomic に差し替えるといった場面で使う。 relaxed 順序関係の保証はない。 volatile load を強制するといった観点での volatile は を使うのが正しい。 load(std::memory_order_relaxed) C++11 的には順序関係が規定されない複数スレッドによる同一アドレスへのアクセスは race バグとなったので。 std::atomic<bool> g_stop; bool g_stop2; int loop() { int n = 0; while( g_stop.load(std::memory_order_relaxed) ) ++n; return n; } int loop2() { int n = 0; while( g_stop2 ) ++n; return n; } これをコンパイルすると、loop2 は無限ループになるが、loop はならない。
  8. loop(): xorl %eax, %eax jmp .L2 .L3: addl $1, %eax

    .L2: movzbl g_stop(%rip), %edx testb %dl, %dl jne .L3 rep; ret loop2(): cmpb $0, g_stop2(%rip) je .L8 .L7: jmp .L7 .L8: xorl %eax, %eax ret CAS Compare and swap 操作には weak と strong がある。weak は spurious failure がありえる アーキテクチャ用ということで、たぶん ll/sc を念頭に置いているんだろう。で、ll/sc で CAS を エミュレートするとループが必要になるけど、CAS 自体もループを伴うことが多いので、それを最適化 するために weak と strong 二つ用意した、らしい。 x86 なら strong だけでいいだろうけど、weak つかってちょいと expect をチェックするループに してやる手間で汎用的なコードになるなら、weak で書くのがいいっぽい。 以下によると、ループするなら weak, ループがないなら strong と言っているんだが、 Strong Compare and Exchange strong が必要な例は正直あまりなさそう。 compare_exchange_strong vs compare_exchange_weak