setter関数について (実装別コピー回数)

2014年9月23日火曜日

プログラム

t f B! P L
C++では、setter関数を書くとき、
  1. void setter(type val) { var = val; }
  2. void setter(const type& val) { var = val; }
  3. void setter(const type& val) { var = val; }
    void setter(type&& val) { var = std::move(val); }
  4. template<typename T>
    void setter(T&& val)
    { var = std::forward<T>(val); }
  5. void setter(type val) { var = std::move(val); }
と、様々な書き型ができます。3〜5はC++11から使えるようになりました。

結論から書くと、
  • intやfloatなら1で
  • std::stringなどmoveが軽く、コピーできるなら5で
  • 派生クラスなどコピーできないなら、2で
  • 自前クラスでmoveが重く、コピーもできて、
    どうしても高速化したいなら、3で
という感じで使い分けるのがいいんじゃないかな?
4は3を1行で書いてるだけなので、普段は使いにくいかと。

3で全部書くから5は使わないという方針もありですが、
同じ関数を何個も書くのは資源の無駄ですし、
5を取り入れるのはいい考えだと思います。

最後に、それぞれの処理内容を比べてみましょう。
  1. lvalueだと関数呼び出し時のコピー1回、代入時のコピー1回
    rvalueだと関数呼び出し時のコピーは省略、代入時のコピー1回
  2. lvalueだと関数呼び出しは参照渡し、代入時のコピー1回
    rvalueだと関数呼び出し時は参照渡し、代入時のコピー1回
  3. lvalueだと関数呼び出しは参照渡し、代入時のコピー1回
    rvalueだと関数呼び出しは参照渡し、代入時のムーブ1回
  4. lvalueだと関数呼び出しは参照渡し、代入時のコピー1回
    rvalueだと関数呼び出しは参照渡し、代入時のムーブ1回
  5. lvalueだと関数呼び出し時のコピー1回、代入時のムーブ1回
    rvalueだと関数呼び出し時のコピーは省略、代入時のムーブ1回
ここでは、rvalueそのものを作成するコンストラクタ、例えば、
“setName(std::string("str"));”のstd::stringのコンストラクタ部分は
数えていません。

ムーブができるようになったので、5のコスト低下が顕著です。
また、5の場合内部でメモリ確保をしないので、noexceptionが
つけれます。そんな感じで5はなかなかいい選択肢になってます。

ラベル

AndroidTV (1) chromebook (2) DIY (4) docker (1) git (4) Ingress (4) llvm (3) MacBook (1) MVNO (1) narou (1) PS4 (2) QNAPNAS (9) SIMD (9) SmartBand (8) Ubuntu (9) VAIO (1) Windows (2) wsl (2) wsl2 (1) Xperia (20) トルネ (3) プログラム (26) ルーター (18) 音楽 (6) 家事 (2) 自炊 (2) 電子書籍 (2) 洋食 (4)

フォロワー

QooQ