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

Effective Modern C++ Item19, Item20

Effective Modern C++ Item19, Item20

shared_ptr と weak_ptr の概要および内部的な話など.
Effective Modern C++ 読書会 4/22(水)

Linda_pp

April 22, 2015
Tweet

More Decks by Linda_pp

Other Decks in Programming

Transcript

  1. std::shared_ptr • Ϧιʔεͷॴ༗ݖΛࢀরΧ΢ϯτʹΑͬͯ؅ཧ͢ ΔϙΠϯλΫϥε • ϦιʔεΛॴ༗͍ͯ͠Δ shared_ptr ͷ਺ΛΧ΢ ϯτ͓͖ͯ͠ɼΧ΢ϯτ͕ 0

    ʹͳͬͨ࣌ʹϦ ιʔεͷσετϥΫλΛ࣮ߦ͢Δ • GC ͷΑ͏ʹࣗಈ؅ཧ͞ΕɼϦιʔεͷղ์λ Πϛϯά͕༧ଌՄೳͰ͋Δɽ Q
  2. { std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }

    } std::shared_ptr 8JEHFU  Q DPOTUSVDU DPOTUSVDU Q
  3. { std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }

    } std::shared_ptr 8JEHFU  Q Q DPOTUSVDU Q
  4. { std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }

    } std::shared_ptr 8JEHFU  Q Q EFTUSPZ Q
  5. { std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }

    } std::shared_ptr 8JEHFU  Q EFTUSPZ EFTUSPZ Q
  6. ࢀরΧ΢ϯτͷίετͷճආ • move ίϯετϥΫλΛ࢖͏ͱࢀরΧ΢ϯτ ͸มԽ͠ͳ͍ʢॴ༗ݖͷҠৡʣ ! ! • ʢ͜ͷଞʹ΋஋౉͠Ͱͳ͘ࢀর౉͠ʹ͢Δͳ ͲͰࢀরΧ΢ϯτͷ্ԼΛ๷͛Δʣ

    Q std::shared_ptr<int> p1{new int}; ! // ࢀরΧ΢ϯτ͸มԽͤͣɼp1 ʹ͸ null ͕୅ೖ͞ΕΔ std::shared_ptr<int> p2{ std::move(p1) };
  7. shared_ptr ͷσϦʔλ • unique_ptr ͱ͸ҧ͍ɼσϦʔλ͕ܕͷҰ෦Ͱ ͸ͳ͍ʢtype erasure ʹΑΔ࣮૷ʣ auto loggingDel

    = [](Widget *pw) { makeLogEntry(pw); delete pw; }; ! std::unique_ptr<Widget, decltype(loggingDel)> upw(new Widget, loggingDel); ! std::shared_ptr<Widget> spw(new Widget, loggingDel); Q
  8. shared_ptr ͷσϦʔλ • ҟͳΔσϦʔλΛ࣋ͭෳ਺ͷ shared_ptr Λ1 ͭͷίϯςφͰ؅ཧͨ͠Γɼޓ͍ʹ୅ೖͰ͖ ͨΓ͢Δ ! !

    ! • ݸਓతʹ͸͜ΕͰԿ͕خ͍͠ͷ͔Α͘෼͔Βͳ͍Ͱ͕͢ɼͲ͏ͤ control block ΍ࢀরΧ΢ϯτͳͲΛผ్ׂ Γ౰ͯΔͳΒ type erasure Ͱফ͠ͱ͚ͱ͍͏ײ͡ͳͷ͔ͳ… auto customDeleter1 = [](Widget *pw) { ... }; auto customDeleter2 = [](Widget *pw) { ... }; ! std::shared_ptr<Widget> pw1(new Widget, customDeleter1); std::shared_ptr<Widget> pw2(new Widget, customDeleter2); ! std::vector<std::shared_ptr<Widget>> vpw{ pw1, pw2 }; Q
  9. Control Block ͷੜ੒λΠϛϯά • std::make_shared() ͕ݺ͹Εͨ࣌ • unique_ptr ΍ auto_ptr

    Λݩʹ shared_ptr ͕ ͭ͘ΒΕͨ࣌ • ੜϙΠϯλΛݩʹ shared_ptr ͕ͭ͘ΒΕͨ࣌ Q $POUSPM#MPDL͸Ϧιʔεʹର͚ͯͭͩ͠ੜ੒ ͠ͳ͚Ε͹ͳΒͳ͍ʢϓϩάϥϚͷ੹೚ʣ
  10. Control Block ͕ॏෳ͢Δྫ ಉ͡ੜϙΠϯλΛݩʹ2ճ shared_ptr Λੜ੒ ͢Δͱ Control Block ͕ॏෳͯ͠͠·͏

    auto pw = new Widget; ! std::shared_ptr<Widget> spw1(pw, loggingDel); // Control Block ੜ੒ ! std::shared_ptr<Widget> spw2(pw, loggingDel); // 2ͭ໨Λੜ੒ ! // spw1 ͱ spw2 ͸ͦΕͧΕผݸʹ pw Λ؅ཧͯ͠͠·͍ͬͯΔͷͰɼ // σϦʔλ͸2ճݺ͹Εͯ͠·͏ʢະఆٛಈ࡞ʣ Q
  11. Control Block ͕ॏෳ͢Δྫ • جຊతʹ͸ std::make_shared() Λ࢖͏΂͖ • ੜϙΠϯλ͔ΒͰ͸ͳ͘ shared_ptr

    ͔Β shared_ptr Λੜ੒͢Δ ! ! ! • ࠓճ͸ΧελϜΞϩέʔλΛࢦఆ͍ͯ͠ΔͷͰ make_shared ͸࢖͑ͳ͍ɽͳ͓ɼΞϩ έʔλΛࢦఆ͍ͨ͠৔߹͸ std::allocate_shared() ͕͋Δɽʢmake_shared_with_deleter() ͕΄͠ ͍ʣ auto pw = new Widget; ! std::shared_ptr<Widget> spw1(pw, loggingDel); // Control Block ੜ੒ ! std::shared_ptr<Widget> spw2(spw1); // OK Q
  12. Control Block ͕ॏෳ͢Δྫ this ͔Β shared_ptr Λੜ੒͢Δ৔߹ std::vector<std::shared_ptr<Widget>> processedWidgets; !

    class Widget{ public: … void process(); … }; ! void Widget::process() { … processedWidgets.emplace_back(this); } Q
  13. Control Block ͕ॏෳ͢Δྫ this ͸ੜϙΠϯλͳͷͰɼprocess() ͕ݺ͹Ε Δͨͼʹ৽͍͠ Control Block ͕ͭ͘ΒΕΔ

    // ຊʹ͸ॻ͍ͯ·ͤΜ͕ɼ͜͏͍͏͜ͱ͕΍Γ͍ͨ͸ͣ ! std::shared_ptr<Widget> spw = std::make_shared(…); ! spw->process(); // NG ผͷ Control Block ͕ͭ͘ΒΕͯ͠·͏ Q
  14. Control Block ͕ॏෳ͢Δྫ std::enable_shared_from_this Ϋϥεςϯϓ ϨʔτΛ࢖͏͜ͱͰղܾ Q // Curiously Recurring

    Template Pattern (CRTP) Λ࢖࣮ͬͯ૷͞Ε͍ͯΔ class Widget : public std::enable_shared_from_this<Widget> { … }; ! void Widget::process() { … processedWidgets.emplace_back(shared_from_this()); }
  15. std::enable_shared_from_this • ܧঝ͢Δͱϝϯόؔ਺ shared_from_this() ͕࢖͑ΔΑ͏ʹͳ ΔΫϥεςϯϓϨʔτ • shared_from_this() ͸ Control-Block

    Λͭ͘Βͣʹ shared_ptr Λ࡞੒͢Δ • Control-Block ͕ແ͍৔߹͸ະఆٛಈ࡞ʢ͍͍ͨͯ͸ྫ֎ʣ • Control-Block ͕طʹ࡞੒͞Ε͍ͯΔඞཁ͕͋Δʢଞͷ shared_ptr ͕ͦͷΦϒδΣΫτΛࢦ͍ͯ͠Δඞཁ͕͋Δʣ Q
  16. std::enable_shared_from_this enable_shared_from_this Λܧঝͨ͠Ϋϥε͸ ඞͣ shared_ptr Ͱ؅ཧ͞ΕΔΑ͏ʹϑΝΫτ Ϧؔ਺Λͭ͘Δ class Widget :

    public std::enable_shared_from_this<Widget> { public: template<typename… Ts> static std::shared_ptr<Widget> create(Ts &&… params) { return std::shared_ptr<Widget>{new Widget(std::forward<Ts>(params)…)}; } … ! private: … // ίϯετϥΫλఆٛ } Q
  17. shared_ptr ͷίετ͸ reasonable • Control Block ͷαΠζ͸σϑΥϧτͰ3word • Control Block

    ͸࣮૷ʹԾ૝ؔ਺Λ࢖͍ͬͯΔ ͕ݺ͹ΕΔͷ͸Ϧιʔε͕ഁغ͞ΕΔ1ճͷΈ • େ఍ͷϚγϯͰ͸ atomic ͳૢ࡞͸1໋ྩͰ࣮ ߦͰ͖Δ Q
  18. ഑ྻͷ؅ཧ • C++14 ࣌఺Ͱ͸ shared_ptr<T []> ͸ߟྀ͞Ε͍ͯ ͳ͍ • std::vector

    ͳͲͷίϯςφΛ࢖͏΂͖ • C++17 Ͱ഑ྻͷαϙʔτ͕ఏҊ͞Ε͍ͯΔ ʢN3869, N3920, N3939ʣ • boost::shared_ptr ͸഑ྻରԠࡁΈ Q
  19. ഑ྻͷ؅ཧ • ΧελϜσϦʔλΛ࢖ͬͯ delete T[] ΛݺͿΑ ͏ʹͯ͠΋μϝ • operator[] ͕ແ͍

    • جఈΫϥεͷ shared_ptr ͕೿ੜΫϥεͷΦ ϒδΣΫτΛࢦ͢ͱ͖ɼ഑ྻΛߟྀ͍ͯ͠ ͳ͍ Q
  20. Things to Remember • shared_ptr ͸ෳ਺ͷϙΠϯλʹڞ༗͞ΕΔϝϞϦ΍೚ҙͷϦ ιʔεͷण໋؅ཧΛߦ͑Δ • unique_ptr ͱൺ΂ͯαΠζ΍

    atomic ͳૢ࡞ͳͲͷΦʔόʔϔο υ͕͋Δ • Ϧιʔεͷഁغʹ͸σϑΥϧτͰ delete ͕࢖ΘΕΔ͕ɼΧελ ϜσϦʔλ΋࢖͑ΔɽΧελϜσϦʔλ͸ shared_ptr ͷܕʹӨ ڹΛ༩͑ͳ͍ • ੜϙΠϯλม਺͔Β shared_ptr Λͭ͘Δ͜ͱ͸ۃྗආ͚Δ΂͖ Q
  21. auto spw = std::make_shared<Widget>(); ←ࠓίίʂ ! std::weak_ptr<Widget> wpw(spw); ! std::cout

    << wpw.expired() << std::endl; // false ! spw = nullptr; // Delete Widget object ! std::cout << wpw.expired() << std::endl; // true std::weak_ptr Q 8JEHFU  TQX
  22. auto spw = std::make_shared<Widget>(); ! std::weak_ptr<Widget> wpw(spw); ←ࠓίίʂ ! std::cout

    << wpw.expired() << std::endl; // false ! spw = nullptr; // Delete Widget object ! std::cout << wpw.expired() << std::endl; // true std::weak_ptr Q 8JEHFU  TQX XQX
  23. auto spw = std::make_shared<Widget>(); ! std::weak_ptr<Widget> wpw(spw); ! std::cout <<

    wpw.expired() << std::endl; // false ! spw = nullptr; // Delete Widget object ←ࠓίίʂ ! std::cout << wpw.expired() << std::endl; // true std::weak_ptr Q 8JEHFU  XQX
  24. Race condition auto spw = std::make_shared<Widget>(); ! std::weak_ptr<Widget> wpw(spw); !

    if (!wpw.expired()) { … // ͜͜ͰଞͷεϨουʹΑͬͯ spw ʹ nullptr ͕୅ೖ͞Εͯ͠·͏ … wpw.lock()->do_something(); // ະఆٛಈ࡞ } expired() ͷνΣοΫͷޙʹଞͷεϨουʹ ΑͬͯϦιʔε͕࡟আ͞Εͯ͠·͏ͷͰ͸ʁ Q
  25. Race condition auto spw = std::make_shared<Widget>(); std::weak_ptr<Widget> wpw(spw); ! //

    wpw ͕ expire ͍ͯ͠Δͱ͖͸ spw2 ͸ null ʹͳΔ auto spw2 = wpw.lock(); ! // wpw ͕ expire ͍ͯ͠Δͱ͖͸ std::bad_weak_ptr ͕౤͛ΒΕΔ std::shared_ptr<Widget> spw3(wpw); → weak_ptr::lock() ͔ shared_ptr ͷίϯετϥΫλΛ ࢖͏ Q ※ ݸਓతʹ͸ if (auto spw = wpw.lock()) { … ͷΑ͏ʹॻ͚Δ lock() ͷ΄͏͕Φεεϝ
  26. Ϣʔεέʔε1: Ωϟογϡ Item18ʹैͬͯ Widget Λੜ੒͠ unique_ptr Ͱฦ͢ϑΝΫτϦؔ਺Λ࡞੒ ! ! loadWidget()

    ͸ॲཧ͕ॏ͍ͷͰ Widget ʹৼ ΒΕͨ ID Λ࢖ͬͯΩϟογϡ͍ͨ͠ std::unique_ptr<const Widget> loadWidget(WidgetID id); Q
  27. std::unique_ptr<const Widget> loadWidget(WidgetID id); ! std::shared_ptr<const Widget> fastLoadWidget(WidgetID id) {

    static std::unordered_map<WidgetID, std::weak_ptr<const Widget>> cache; ! // Ωϟογϡ͕ແ͍͔ expire ͍ͯ͠Δ࣌ objPtr ͸ۭʹͳΔ auto objPtr = cache[id].lock(); ! // Ωϟογϡ͞Ε͍ͯͳ͚Ε͹৽͘͠ Widget Λͭ͘ΓɼΩϟογϡ͢Δ if (!objPtr) { objPtr = loadWidget(id); cache[id] = objPtr; } ! return objPtr; } Q Ϣʔεέʔε1: Ωϟογϡ
  28. Ϣʔεέʔε2: Observer • observerʢsubject ͔Β௨஌Λड͚औΓԿ͔ॲཧΛ ߦ͏ʣ • subjectʢঢ়ଶΛ࣋ͪ observer ʹঢ়ଶͷมߋΛ௨஌

    ͢Δʣ • subject ͸ observer Λࢀর͢Δ͕ɼobserver ͸ࢮ͵ ͜ͱ͕͋Δ → subject ͸ observer Λ weak_ptr Ͱ࣋ ͭ΂͖ Q
  29. Ϣʔεέʔε2: Observer ͜Μͳײ͡ʁʢຊจதʹ͸ྫͳ͠ʣ class Subject { public: void register_observer(std::shared_ptr<Observer> const&

    o) { observers.emplace_back(o); } ! void update_state() { for (auto const& w : observers) { if (auto const o = w.lock()) { o->notify(…); } } } ! private: std::vector<std::weak_ptr<Observer>> observers; }; Q
  30. ??? ͷ෦෼ʹԿΛ࢖͑͹ྑ͍͔ • ੜϙΠϯλ → A ͕ഁغ͞Εͨ࣌ʹͦΕΛ஌Δํ๏͕ͳ͍ NG • shared_ptr

    → ॥؀ࢀরͯ͠͠·͍ɼӬԕʹࢀরΧ΢ϯτ ͕ 0 ʹͳΒͳ͘ͳΔʢϝϞϦϦʔΫʣ NG • weak_ptr → A ͕ഁغ͞Ε͍ͯΔ͔Ͳ͏͔Λ஌Δ͜ͱ͕ Ͱ͖ɼA Λॴ༗͍ͯ͠ͳ͍ͷͰ॥؀ࢀর΋ͳ͍ OK • ※໦ߏ଄Ͱ਌ͷΈ͕ࢠΛ shared_ptr Ͱࢦ͢ͱ͍ͬͨಛघͳ৚݅Ͱ͋Ε͹ࢠˠ਌͸ੜϙΠϯλͰ΋ྑ͍ Q
  31. weak_ptr ͷίετ • αΠζ͸ shared_ptr ͱಉ͡ʢshared_ptr ͱಉ ༷ʹ Control Block

    Λར༻͢Δʣ • Χ΢ϯτͷૢ࡞͸ atomic Ͱ͋Δ → ࢀরΧ΢ ϯτͰ͸ͳ͘ऑࢀরΧ΢ϯτΛૢ࡞͢Δ 3FGFSFODF$PVOU 8FBL$PVOU 0UIFS%BUB DVTUPNEFMFUFS BMMPDBUPS  FUD $POUSPM#MPDL • Control Block ͸͢΂ͯͷ weak_ptr ͕ ͍ͳ͘ͳͬͯॳΊͯ࡟আͰ͖ΔͷͰऑ ࢀরΛΧ΢ϯτ͢Δඞཁ͕͋ΔʢItem 21ʣ Q
  32. Things to Remember • Ϧιʔε͕ແޮʹͳΔ͜ͱ͕͋Δ shared_ptr ͷΑ͏ͳϙΠϯλ͕΄͍࣌͠͸ std::weak_ptr Λ࢖͏ •

    weak_ptr ͷओͳϢʔεέʔε͸Ωϟογϡɼ Φϒβʔόɼ॥؀ࢀরͷճආͳͲ Q