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?

    View full-size slide

  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?
    短く言うと、引数も返り値も値渡しで書けばいい。

    View full-size slide

  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.

    View full-size slide

  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(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

    View full-size slide

  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 typename T;
    template
    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 スレッドが終わったらプロセスごと消えちゃう。

    View full-size slide

  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
    #include
    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 a{0};
    std::atomic 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

    View full-size slide

  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 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 はならない。

    View full-size slide

  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

    View full-size slide