Effective Modern C++ 読書会 Item29, Item30

Effective Modern C++ 読書会 Item29, Item30

Item29: move に期待しすぎないようにしよう
Item30: perfect forwarding に失敗する場合を知ろう

Dea1add99f4cf942792c0f185aa2f2fd?s=128

Linda_pp

July 16, 2015
Tweet

Transcript

  1. Effective Modern C++ ಡॻձ Item29, Item 30 @Linda_pp @rhysd

  2. Item 29: moveʹظ଴͗͢͠Δͳ ʢAssume that move operations are not present,

    not cheap, and not used)
  3. move • move ͸ C++11 ͷ໨ۄػೳͷͻͱͭ • C++03 ͷίʔυ΋ C++11

    ͰϏϧυ͠ͳ͓ͤ͹ ଎͘ͳΔʂ • STL ͸ move ରԠ • ίϯςφͷίϐʔ͕ϙΠϯλ1ͭͷίϐʔʹͳΔ ͧʂ
  4. ࣮ࡍ͸ move ͕ࢥͬͨ΄Ͳ༗ ༻Ͱͳ͍৔߹͕ͨ͘͞Μ͋Δ

  5. move ૢ࡞͕ଘࡏ͠ͳ͍࣌ ҉໧ͷ move Λఆٛ͞ΕΔ৚͕݅ݫ͍͠  • copyૢ࡞ɼmoveૢ࡞ɼσετϥΫλ͕ Ϣʔβఆٛ͞Ε͍ͯͳ͍ (Item17)

    • جఈΫϥε͕moveඇରԠͰͳ͍ (Item11)
  6. move ૢ࡞ͷίετ͕௿͘ͳ ͍࣌ ΄ͱΜͲͷ STL ίϯςφͷ move → ώʔϓ΁ ͷϙΠϯλ

    ͷషΓସ͚͑ͩͰྑ͍ʢ O(1) ʣ  DPOUBJOFS CV⒎FS DPOUBJOFS NPWF
  7. move ૢ࡞ͷίετ͕௿͘ͳ ͍࣌ std::array → ֤ཁૉͷ move ͔͠Ͱ͖ͳ͍ʢ O(n) ʣ

     TUEBSSBZ CV⒎FS NPWF TUEBSSBZ CV⒎FS
  8. move ૢ࡞ͷίετ͕௿͘ͳ ͍࣌ std::string →Small String Optimization  • খ͍͞จࣈྻ͸

    stack ʹऔΔ • 64bit OS, libc++ ͳΒ 24 จࣈ·Ͱ • move ͸ std::array ͷΑ͏ʹ 0(n) ͔͔Δ
  9. move ૢ࡞͕࢖͑ͳ͍࣌ ྫ֎҆શͳૢ࡞Λఏڙ͢Δίϯςφʢྫɿ std::vector ͷιʔτʣ → ཁૉͷ move ͕ྫ֎Λ౤ ͛Δͱ͖

    copy ʹ fallback  • ཁૉͷ move தʹྫ֎͕ൃੜ͢Δͱ vector ͷ move ͕׬ྃͰ͖ͳ͍
  10. move ͕༗ޮͰͳ͍࣌·ͱΊ • move ૢ࡞͕ଘࡏ͠ͳ͍ͱ͖ → ҉໧ͷ move ৚݅͸ݫ͍͠ •

    move ૢ࡞͕଎͘ͳ͍ͱ͖ → std::array • move ૢ࡞͕࢖͑ͳ͍ͱ͖ → std::vector ͷཁૉ͕ྫ֎҆શ ʹ move Ͱ͖ͳ͍࣌ • lvalue ͷͱ͖ → Ұ෦ͷྫ֎ʢ҉໧ͷ moveʣΛআ͍ͯ lvalue ͸ move Ͱ͖ͳ͍
  11. Things to Remember • ςϯϓϨʔτΛ࢖͍ͬͯΔ࣌͸ͲΜͳܕ͕౉ͬ ͯ͘Δ͔Θ͔Βͳ͍ → move ʹ͍ͭͯ͸อक తʹίʔυΛॻ͘

    • ѻ͏ܕͷৄࡉ͕෼͔͍ͬͯΔ → ܕͷυΩϡϝ ϯτΛಡΜͰ move ͕༗༻Ͱ͋Ε͹ͦΕʹґ ଘͨ͠ίʔυΛॻ͍ͯྑ͍
  12. Item 30: perfect forwarding ʹࣦഊ͢Δ৔߹Λ஌Ζ͏

  13. Perfect Forwarding Universal Reference Λ࢖͍ɼؔ਺ͷҾ਺Λ (const-ness ౳΋ؚΊͯʣผͷؔ਺ݺͼग़͠ʹ ͦͷ··సૹ͢Δ  1

    // perfect forward する関数 fwd 2 template<class... Ts> 3 auto fwd(Ts&& ... args) 4 { 5 // 関数 f に引数をそのまま転送する 6 return f(std::foward<Ts>(args)...); 7 } 8 9 ... 10 11 // 引数によっては perfect forwarding が失敗する 12 fwd({expression});
  14. Perfect Forwarding ͕͏·͘ ͍͔ͳ͍Τοδέʔε ɾ{} ʹΑΔॳظԽ ɾ0 ΍ NULL ΛψϧϙΠϯλͱͯ͠࢖͏

    ɾએݴ͚ͩͷ static const ·ͨ͸ constexpr σʔλϝϯό ɾΦʔόʔϩʔυ͞Εͨؔ਺ ɾؔ਺ςϯϓϨʔτ ɾϏοτϑΟʔϧυ 
  15. {} ʹΑΔॳظԽ 1 void f(const std::vector<int>&); 2 3 ... 4

    5 // OK. std::vector<int> は {1, 2, 3} で初期化される 6 f( {1, 2, 3} ); 7 8 // コンパイルエラー! 9 fwd( {1, 2, 3} ); foo.cpp:15:5: error: no matching function for call to 'fwd' fwd({1, 2, 3}); ^~~ ! foo.cpp:8:6: note: candidate function not viable: requires 0 arguments, but 1 was provided void fwd(Args &&... args) ^ 1 error generated. 
  16. {} ʹΑΔॳظԽ • f Λ௚઀ݺͼग़ͨ͠৔߹ɼίϯύΠϥ͸ f ͷҾ ਺͔Β {1,2,3} Λ

    vector ʹ҉໧ม׵͢Ε͹ྑ ͍͜ͱ͕෼͔Δ • fwd Λ࢖ͬͯؒ઀తʹݺͼग़ͨ͠৔߹ɼfwd ͷҾ਺͸ Universal Reference ͷͨΊɼ{1,2,3} ΛͲͷܕʹม׵͢Ε͹ྑ͍ͷ͔෼͔Βͳ͍
  17. ͳͥ std::initializer_list<int> ʹ ͳΒͳ͍ͷ͔ • Ҿ਺͕ std::initializer_list ͱ໌ࣔ͞Ε͍ͯͳ͍ ݶΓɼinitializer_list ʹ͸ਪ࿦͞Εͳ͍ʢnon-

    deduced contextʣ • ҎԼͷ৔߹ auto ͷਪ࿦͸ OK 1 // auto が std::initializer_list<int> に推論される 2 auto il = {1, 2, 3}; 3 4 // OK.すでに推論済み 5 fwd(il);
  18. 0 ΍ NULL ΛψϧϙΠϯλʹ ࢖ͬͨ৔߹ 0 ΍ NULL ͸੔਺ܕʹਪ࿦͞Εͯ͠·͏ͨΊ ϙΠϯλʹม׵Ͱ͖ͳ͍ʢItem8ʣˠ

    nullptr Λ࢖͑͹OK  1 void f(int *) 2 {} 3 4 template<class... Args> 5 void fwd(Args &&... args) 6 { 7 return f(std::forward<Args>(args)...); 8 } 9 10 fwd(NULL);
  19. એݴ͚ͩͷ static const ·ͨ͸ constexpr σʔλϝϯό Undefined symbols for architecture

    x86_64: "Widget::MinVals", referenced from: _main in foo-4cf4cf.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) ! ※ clang 3.4 ͙Β͍·Ͱ͸ίϯύΠϧ௨ͬͯ͠·͏  1 struct Widget { 2 static constexpr int MinVals = 28; // 定義ではなく宣言 3 }; 4 5 void f(size_t val); 6 7 ... 8 9 f(Widget::MinVals); // OK 10 11 fwd(Widget::MinVals); // リンクエラー
  20. એݴ͚ͩͷ static const ·ͨ͸ constexpr σʔλϝϯό • f ͷ৔߹͸ MinVals

    ͷ஋͕஋౉͠͞ΕΔͷͰ OK • fwd ͷ৔߹ɼUniversal Reference ͸ࢀরͳͷ ͰɼMinVals ͷΞυϨε͕ඞཁʹͳΔ → Ϧϯ ΫΤϥʔ • ԼهͷΑ͏ʹ࣮ମΛఆ͓͚ٛͯ͠͹ OK const size_t Widget::MinVals;
  21. Φʔόʔϩʔυ͞Εͨؔ਺ foo.cpp:24:5: error: no matching function for call to 'fwd'

    fwd(processVal); ^~~ foo.cpp:17:6: note: candidate function not viable: requires 0 arguments, but 1 was provided void fwd(Args &&... args) ^ 1 error generated.  1 int processVal(int val); 2 int processVal(int val, int priority); 3 4 void f(int (*fp)(int)); 5 6 ... 7 8 f(processVal); // OK 9 10 fwd(processVal); // コンパイルエラー!
  22. Φʔόʔϩʔυ͞Εͨؔ਺ • f ͷݺͼग़͠Ͱ͸Ҿ਺ͷܕ͔Β processVal ͷ ΦʔόʔϩʔυΛղܾͰ͖Δ • fwd ͷݺͼग़͠Ͱ͸Ҿ਺͸

    Universal Reference ͷͨΊɼprocessVal ͷΦʔόʔ ϩʔυ͕ղܾͰ͖ͳ͍ • ԼهͷΑ͏ͳ৔߹͸ OK int (*p)(int) = processVal; // ͜͜ͰΦʔόʔϩʔυղܾࡁΈ fwd(p); // OK
  23. ؔ਺ςϯϓϨʔτ Φʔόʔϩʔυͷ৔߹ͱ࿩͸ಉ͡  1 template<class T> 2 int processVal(T val);

    3 4 void f(int (*fp)(int)); 5 6 ... 7 8 f(processVal); // OK 9 10 fwd(processVal); // T が解決できないため NG
  24. ϏοτϑΟʔϧυ  foo.cpp:25:9: error: non-const reference cannot bind to bit-field

    'totalLength' fwd(h.totalLength); ^~~~~~~~~~~~~ foo.cpp:9:17: note: bit-field is declared here totalLength:16; ^ 1 error generated. 1 struct IPv4Header { 2 std::uint32_t version:4, 3 IHL:4, 4 DSCP:6, 5 ECN:2, 6 totalLength:16; 7 }; 8 9 void f(size_t s); 10 11 ... 12 13 IPv4Header h; 14 15 f(h.totalLength); // OK 16 fwd(h.totalLength); // コンパイルエラー!
  25. ϏοτϑΟʔϧυ • ϏοτϑΟʔϧυ΁ͷΞΫηε͸ඇconstࢀর → fwd ͷҾ਺͸ඇconstࢀরʹͳΔ → Ϗοτ ϑΟʔϧυ͸ඇconstࢀরʹଋറͰ͖ͳ͍ •

    ಛఆͷϏοτϑΟʔϧυΛࢦ͢ϙΠϯλ͕ͭ ͘Εͳ͍ͷͱಉ͡ • ίϐʔΛͭ͘Ε͹ OK 1 IPv4Header h; 2 3 auto length = static_cast<std::uint16_t>(totalLength); 4 5 fwd(length); // OK
  26. ·ͱΊ • Perfect Forwarding ͸େ఍ͷ৔߹͸ࢥͬͨ௨ Γಈ͘ • ྫʹग़ͨΑ͏ͳكʹ͏·͍͔͘ͳ͍έʔε͕ ͋Δ •

    ϫʔΫΞϥ΢ϯυΛ஌͓ͬͯ͘ͷ͕େࣄ
  27. Things to Remember • Perfect Forwarding ࣦഊ͢Δ৔߹ • సૹؔ਺ͷҾ਺ͷܕͷਪ࿦ʹࣦഊͨ࣌͠ •

    సૹؔ਺ͷҾ਺ͷܕΛؒҧͬͨʢf ʹ౉ͤͳ͍ʣܕʹਪ࿦ͯ͠͠·ͬͨ࣌ • ͦͷଞͷΤοδέʔε • {} ʹΑΔॳظԽ • 0 ΍ NULL ΛψϧϙΠϯλͱͯ͠࢖͏ • એݴ͚ͩͷ static const ·ͨ͸ constexpr σʔλϝϯό • Φʔόʔϩʔυ͞Εͨؔ਺ • ؔ਺ςϯϓϨʔτ • ϏοτϑΟʔϧυ