Slide 1

Slide 1 text

Effective Modern C++ ಡॻձ Item 19, Item 20

Slide 2

Slide 2 text

@Linda_pp @rhysd झຯͰίϯύΠϥͱ͔ͭͬͯ͘·͢ɽ https://github.com/rhysd/Dachs

Slide 3

Slide 3 text

Item 19: ॴ༗ݖΛڞ༗͍ͨ͠Ϧ ιʔεͷ؅ཧʹ͸ std::shared_ptr Λ࢖͓͏

Slide 4

Slide 4 text

C++ ʹ͓͚ΔϝϞϦ؅ཧ Q.ʮͳΜͯݪ࢝తͳΜͩʂ1960೥୅ͷLisp ʹԿ΋ֶ͹ͳ ͔ͬͨͷ͔ʁϦιʔε͸ਓؒͰͳ͘Ϛγϯ͕؅ཧ͢΂͖ͩʯ ! A.ʮϝϞϦ͚͕ͩϦιʔεͰ͸ͳ͍͠ɼϝϞϦ͕։์͞Ε ΔλΠϛϯά͕෼͔Βͳ͍ͷ͸ࠔΔɽԶୡ͸ී௨ͷ༧ଌͰ ͖ΔσετϥΫλ͕ྑ͍Μͩɽʯ Q

Slide 5

Slide 5 text

C++ ʹ͓͚ΔϝϞϦ؅ཧ ͦ͏͸͍ͬͯ΋΍͸Γ GC ͸ศརɽGCͱϝϞ Ϧखಈ؅ཧͷؒͷଘࡏ͕΄͍͠ɽ → std::shared_ptr Q

Slide 6

Slide 6 text

std::shared_ptr • Ϧιʔεͷॴ༗ݖΛࢀরΧ΢ϯτʹΑͬͯ؅ཧ͢ ΔϙΠϯλΫϥε • ϦιʔεΛॴ༗͍ͯ͠Δ shared_ptr ͷ਺ΛΧ΢ ϯτ͓͖ͯ͠ɼΧ΢ϯτ͕ 0 ʹͳͬͨ࣌ʹϦ ιʔεͷσετϥΫλΛ࣮ߦ͢Δ • GC ͷΑ͏ʹࣗಈ؅ཧ͞ΕɼϦιʔεͷղ์λ Πϛϯά͕༧ଌՄೳͰ͋Δɽ Q

Slide 7

Slide 7 text

{ std::shared_ptr p1{new Widget}; { auto p2 = p1; } } std::shared_ptr 8JEHFU Q DPOTUSVDU DPOTUSVDU Q

Slide 8

Slide 8 text

{ std::shared_ptr p1{new Widget}; { auto p2 = p1; } } std::shared_ptr 8JEHFU Q Q DPOTUSVDU Q

Slide 9

Slide 9 text

{ std::shared_ptr p1{new Widget}; { auto p2 = p1; } } std::shared_ptr 8JEHFU Q Q EFTUSPZ Q

Slide 10

Slide 10 text

{ std::shared_ptr p1{new Widget}; { auto p2 = p1; } } std::shared_ptr 8JEHFU Q EFTUSPZ EFTUSPZ Q

Slide 11

Slide 11 text

ࢀরΧ΢ϯτͷίετ • shared_ptr ͷαΠζ → ੜϙΠϯλͷ2ഒʢ࣮ ࡍʹ͸ίϯτϩʔϧϒϩοΫ΋ʢޙड़ʣʣ • ϝϞϦϦιʔε͸ಈతʹ֬อ͢Δඞཁ͕͋Δ • ࢀরΧ΢ϯτͷૢ࡞͸ atomic Ͱ͋Δ (thread safety) Q

Slide 12

Slide 12 text

ࢀরΧ΢ϯτͷίετͷճආ • move ίϯετϥΫλΛ࢖͏ͱࢀরΧ΢ϯτ ͸มԽ͠ͳ͍ʢॴ༗ݖͷҠৡʣ ! ! • ʢ͜ͷଞʹ΋஋౉͠Ͱͳ͘ࢀর౉͠ʹ͢Δͳ ͲͰࢀরΧ΢ϯτͷ্ԼΛ๷͛Δʣ Q std::shared_ptr p1{new int}; ! // ࢀরΧ΢ϯτ͸มԽͤͣɼp1 ʹ͸ null ͕୅ೖ͞ΕΔ std::shared_ptr p2{ std::move(p1) };

Slide 13

Slide 13 text

shared_ptr ͷσϦʔλ • unique_ptr ͱ͸ҧ͍ɼσϦʔλ͕ܕͷҰ෦Ͱ ͸ͳ͍ʢtype erasure ʹΑΔ࣮૷ʣ auto loggingDel = [](Widget *pw) { makeLogEntry(pw); delete pw; }; ! std::unique_ptr upw(new Widget, loggingDel); ! std::shared_ptr spw(new Widget, loggingDel); Q

Slide 14

Slide 14 text

shared_ptr ͷσϦʔλ • ҟͳΔσϦʔλΛ࣋ͭෳ਺ͷ shared_ptr Λ1 ͭͷίϯςφͰ؅ཧͨ͠Γɼޓ͍ʹ୅ೖͰ͖ ͨΓ͢Δ ! ! ! • ݸਓతʹ͸͜ΕͰԿ͕خ͍͠ͷ͔Α͘෼͔Βͳ͍Ͱ͕͢ɼͲ͏ͤ control block ΍ࢀরΧ΢ϯτͳͲΛผ్ׂ Γ౰ͯΔͳΒ type erasure Ͱফ͠ͱ͚ͱ͍͏ײ͡ͳͷ͔ͳ… auto customDeleter1 = [](Widget *pw) { ... }; auto customDeleter2 = [](Widget *pw) { ... }; ! std::shared_ptr pw1(new Widget, customDeleter1); std::shared_ptr pw2(new Widget, customDeleter2); ! std::vector> vpw{ pw1, pw2 }; Q

Slide 15

Slide 15 text

shared_ptr ͷαΠζ • unique_ptr ͱ͸ҟͳΓɼৗʹϙΠϯλ2ͭ෼ • ͋ΕɼͰ΋ΧελϜσϦʔλͷαΠζ͸…ʁ • → ΧελϜσϦʔλͳͲ͸ผͷ৔ॴʹ֬อ ͞ΕΔʢޙड़ʣ Q

Slide 16

Slide 16 text

shared_ptr ͷ಺෦ߏ଄ 1PJOUFSUP5 1PJOUFSUP$POUSPM#MPDL 50CKFDU 3FGFSFODF$PVOU 8FBL$PVOU 0UIFS%BUB DVTUPNEFMFUFS BMMPDBUPS FUD TIBSFE@QUS5 $POUSPM#MPDL 3FTPVSDF Q

Slide 17

Slide 17 text

Control Block • ࢀরΧ΢ϯτ΍ऑࢀরΧ΢ϯτͳͲͷ؅ཧ৘ ใΛ࣋ͭ • ؅ཧର৅ͷΦϒδΣΫτ͕ੜ੒͞Εͨ࣌ʹ1౓ ͚ͩੜ੒͞ΕΔ • Χ΢ϯτ͕྆ํ0ʹͳͬͨ࣌ʹഁغ͞ΕΔ Q

Slide 18

Slide 18 text

Control Block ͷੜ੒λΠϛϯά • std::make_shared() ͕ݺ͹Εͨ࣌ • unique_ptr ΍ auto_ptr Λݩʹ shared_ptr ͕ ͭ͘ΒΕͨ࣌ • ੜϙΠϯλΛݩʹ shared_ptr ͕ͭ͘ΒΕͨ࣌ Q $POUSPM#MPDL͸Ϧιʔεʹର͚ͯͭͩ͠ੜ੒ ͠ͳ͚Ε͹ͳΒͳ͍ʢϓϩάϥϚͷ੹೚ʣ

Slide 19

Slide 19 text

Control Block ͕ॏෳ͢Δྫ ಉ͡ੜϙΠϯλΛݩʹ2ճ shared_ptr Λੜ੒ ͢Δͱ Control Block ͕ॏෳͯ͠͠·͏ auto pw = new Widget; ! std::shared_ptr spw1(pw, loggingDel); // Control Block ੜ੒ ! std::shared_ptr spw2(pw, loggingDel); // 2ͭ໨Λੜ੒ ! // spw1 ͱ spw2 ͸ͦΕͧΕผݸʹ pw Λ؅ཧͯ͠͠·͍ͬͯΔͷͰɼ // σϦʔλ͸2ճݺ͹Εͯ͠·͏ʢະఆٛಈ࡞ʣ Q

Slide 20

Slide 20 text

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 spw1(pw, loggingDel); // Control Block ੜ੒ ! std::shared_ptr spw2(spw1); // OK Q

Slide 21

Slide 21 text

Control Block ͕ॏෳ͢Δྫ this ͔Β shared_ptr Λੜ੒͢Δ৔߹ std::vector> processedWidgets; ! class Widget{ public: … void process(); … }; ! void Widget::process() { … processedWidgets.emplace_back(this); } Q

Slide 22

Slide 22 text

Control Block ͕ॏෳ͢Δྫ this ͸ੜϙΠϯλͳͷͰɼprocess() ͕ݺ͹Ε Δͨͼʹ৽͍͠ Control Block ͕ͭ͘ΒΕΔ // ຊʹ͸ॻ͍ͯ·ͤΜ͕ɼ͜͏͍͏͜ͱ͕΍Γ͍ͨ͸ͣ ! std::shared_ptr spw = std::make_shared(…); ! spw->process(); // NG ผͷ Control Block ͕ͭ͘ΒΕͯ͠·͏ Q

Slide 23

Slide 23 text

Control Block ͕ॏෳ͢Δྫ std::enable_shared_from_this Ϋϥεςϯϓ ϨʔτΛ࢖͏͜ͱͰղܾ Q // Curiously Recurring Template Pattern (CRTP) Λ࢖࣮ͬͯ૷͞Ε͍ͯΔ class Widget : public std::enable_shared_from_this { … }; ! void Widget::process() { … processedWidgets.emplace_back(shared_from_this()); }

Slide 24

Slide 24 text

std::enable_shared_from_this • ܧঝ͢Δͱϝϯόؔ਺ shared_from_this() ͕࢖͑ΔΑ͏ʹͳ ΔΫϥεςϯϓϨʔτ • shared_from_this() ͸ Control-Block Λͭ͘Βͣʹ shared_ptr Λ࡞੒͢Δ • Control-Block ͕ແ͍৔߹͸ະఆٛಈ࡞ʢ͍͍ͨͯ͸ྫ֎ʣ • Control-Block ͕طʹ࡞੒͞Ε͍ͯΔඞཁ͕͋Δʢଞͷ shared_ptr ͕ͦͷΦϒδΣΫτΛࢦ͍ͯ͠Δඞཁ͕͋Δʣ Q

Slide 25

Slide 25 text

std::enable_shared_from_this enable_shared_from_this Λܧঝͨ͠Ϋϥε͸ ඞͣ shared_ptr Ͱ؅ཧ͞ΕΔΑ͏ʹϑΝΫτ Ϧؔ਺Λͭ͘Δ class Widget : public std::enable_shared_from_this { public: template static std::shared_ptr create(Ts &&… params) { return std::shared_ptr{new Widget(std::forward(params)…)}; } … ! private: … // ίϯετϥΫλఆٛ } Q

Slide 26

Slide 26 text

shared_ptr ͷίετ͸ reasonable • Control Block ͷαΠζ͸σϑΥϧτͰ3word • Control Block ͸࣮૷ʹԾ૝ؔ਺Λ࢖͍ͬͯΔ ͕ݺ͹ΕΔͷ͸Ϧιʔε͕ഁغ͞ΕΔ1ճͷΈ • େ఍ͷϚγϯͰ͸ atomic ͳૢ࡞͸1໋ྩͰ࣮ ߦͰ͖Δ Q

Slide 27

Slide 27 text

shared_ptr ͷίετ͸ reasonable • एׯͷίετͱҾ͖׵͑ʹण໋؅ཧΛࣗಈͰ ߦ͑Δ • ͨͩ͠ॴ༗ݖΛڞ༗͢Δඞཁ͕ແ͍ͳΒ unique_ptr ͷ΄͏͕ྑ͍ • unique_ptr ͸ඞཁʹԠͯ͡ shared_ptr ʹ౉ ͤΔ Q

Slide 28

Slide 28 text

഑ྻͷ؅ཧ • C++14 ࣌఺Ͱ͸ shared_ptr ͸ߟྀ͞Ε͍ͯ ͳ͍ • std::vector ͳͲͷίϯςφΛ࢖͏΂͖ • C++17 Ͱ഑ྻͷαϙʔτ͕ఏҊ͞Ε͍ͯΔ ʢN3869, N3920, N3939ʣ • boost::shared_ptr ͸഑ྻରԠࡁΈ Q

Slide 29

Slide 29 text

഑ྻͷ؅ཧ • ΧελϜσϦʔλΛ࢖ͬͯ delete T[] ΛݺͿΑ ͏ʹͯ͠΋μϝ • operator[] ͕ແ͍ • جఈΫϥεͷ shared_ptr ͕೿ੜΫϥεͷΦ ϒδΣΫτΛࢦ͢ͱ͖ɼ഑ྻΛߟྀ͍ͯ͠ ͳ͍ Q

Slide 30

Slide 30 text

Things to Remember • shared_ptr ͸ෳ਺ͷϙΠϯλʹڞ༗͞ΕΔϝϞϦ΍೚ҙͷϦ ιʔεͷण໋؅ཧΛߦ͑Δ • unique_ptr ͱൺ΂ͯαΠζ΍ atomic ͳૢ࡞ͳͲͷΦʔόʔϔο υ͕͋Δ • Ϧιʔεͷഁغʹ͸σϑΥϧτͰ delete ͕࢖ΘΕΔ͕ɼΧελ ϜσϦʔλ΋࢖͑ΔɽΧελϜσϦʔλ͸ shared_ptr ͷܕʹӨ ڹΛ༩͑ͳ͍ • ੜϙΠϯλม਺͔Β shared_ptr Λͭ͘Δ͜ͱ͸ۃྗආ͚Δ΂͖ Q

Slide 31

Slide 31 text

Item20: ࢦ͢Ϧιʔε͕ແޮʹͳΓ ͏Δ shared_ptr ʹ͸ std::weak_ptr Λ࢖͓͏

Slide 32

Slide 32 text

ॴ༗ݖΛ࣋ͨͳ͍ϙΠϯλ • shared_ptr ͷΑ͏ʹಛఆͷϦιʔεΛࢦͤΔ ͕ɼॴ༗ݖ͸࣋ͨͳ͍ʢ=ࢀরΧ΢ϯτΛಈ͔ ͞ͳ͍ʣεϚʔτϙΠϯλ͕΄͍͠ • ͦͷϙΠϯλ͸ࢦ͍ͯ͠ΔϦιʔε͕ଞͷ shared_ptr ʹ࡟আ͞ΕΔՄೳੑ͕͋Δ • ͦΕ std::weak_ptr ͰͰ͖ΔΑʂ Q

Slide 33

Slide 33 text

std::weak_ptr • dereference ΋ null νΣοΫ΋Ͱ͖ͳ͍ • shared_ptr ΁ͷঢ֨ͱࢦ͍ͯ͠ΔϦιʔε͕ ੜ͖͍ͯΔ͔Ͳ͏͔ͷνΣοΫ͕Ͱ͖Δ • shared_ptr ͱҰॹʹ࢖͏ʢ͍͍ͨͯ shared_ptr ͔Βੜ੒͞ΕΔʣ Q

Slide 34

Slide 34 text

auto spw = std::make_shared(); ←ࠓίίʂ ! std::weak_ptr 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

Slide 35

Slide 35 text

auto spw = std::make_shared(); ! std::weak_ptr 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

Slide 36

Slide 36 text

auto spw = std::make_shared(); ! std::weak_ptr 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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Race condition auto spw = std::make_shared(); std::weak_ptr wpw(spw); ! // wpw ͕ expire ͍ͯ͠Δͱ͖͸ spw2 ͸ null ʹͳΔ auto spw2 = wpw.lock(); ! // wpw ͕ expire ͍ͯ͠Δͱ͖͸ std::bad_weak_ptr ͕౤͛ΒΕΔ std::shared_ptr spw3(wpw); → weak_ptr::lock() ͔ shared_ptr ͷίϯετϥΫλΛ ࢖͏ Q ※ ݸਓతʹ͸ if (auto spw = wpw.lock()) { … ͷΑ͏ʹॻ͚Δ lock() ͷ΄͏͕Φεεϝ

Slide 39

Slide 39 text

Ϣʔεέʔε1: Ωϟογϡ Item18ʹैͬͯ Widget Λੜ੒͠ unique_ptr Ͱฦ͢ϑΝΫτϦؔ਺Λ࡞੒ ! ! loadWidget() ͸ॲཧ͕ॏ͍ͷͰ Widget ʹৼ ΒΕͨ ID Λ࢖ͬͯΩϟογϡ͍ͨ͠ std::unique_ptr loadWidget(WidgetID id); Q

Slide 40

Slide 40 text

std::unique_ptr loadWidget(WidgetID id); ! std::shared_ptr fastLoadWidget(WidgetID id) { static std::unordered_map> cache; ! // Ωϟογϡ͕ແ͍͔ expire ͍ͯ͠Δ࣌ objPtr ͸ۭʹͳΔ auto objPtr = cache[id].lock(); ! // Ωϟογϡ͞Ε͍ͯͳ͚Ε͹৽͘͠ Widget Λͭ͘ΓɼΩϟογϡ͢Δ if (!objPtr) { objPtr = loadWidget(id); cache[id] = objPtr; } ! return objPtr; } Q Ϣʔεέʔε1: Ωϟογϡ

Slide 41

Slide 41 text

Ϣʔεέʔε1: Ωϟογϡ • ੜ੒ͨ͠Ϧιʔε͕ഁغ͞Ε͍ͯΔ͔Ͳ͏͔Λ஌Δඞ ཁ͕͋ΔͨΊɼweak_ptr ͰΩϟογϡ͢Δͷ͕ద೚ • Ϧιʔεͷঢ়ଶΛ஌ΔͨΊʹΩϟογϡ෇͖ϑΝΫτ Ϧؔ਺ͷ໭Γ஋͸ shared_ptr ʹ͢Δඞཁ͕͋Δ (Control Block ಺ͷ weak count) • expire ͨ͠Ωϟογϡͷ࡟আͳͲΛ௥Ճͯ͠΋ྑ͍ ͔΋͠Εͳ͍ Q

Slide 42

Slide 42 text

Ϣʔεέʔε2: Observer • observerʢsubject ͔Β௨஌Λड͚औΓԿ͔ॲཧΛ ߦ͏ʣ • subjectʢঢ়ଶΛ࣋ͪ observer ʹঢ়ଶͷมߋΛ௨஌ ͢Δʣ • subject ͸ observer Λࢀর͢Δ͕ɼobserver ͸ࢮ͵ ͜ͱ͕͋Δ → subject ͸ observer Λ weak_ptr Ͱ࣋ ͭ΂͖ Q

Slide 43

Slide 43 text

Ϣʔεέʔε2: Observer ͜Μͳײ͡ʁʢຊจதʹ͸ྫͳ͠ʣ class Subject { public: void register_observer(std::shared_ptr 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> observers; }; Q

Slide 44

Slide 44 text

Ϣʔεέʔε3: σʔλߏ଄ ! ! ! B ͕ A Λࢦ࣌͢ɼԿΛ࢖͑͹ྑ͍͔ # " $ TIBSFE@QUS TIBSFE@QUS Q

Slide 45

Slide 45 text

??? ͷ෦෼ʹԿΛ࢖͑͹ྑ͍͔ • ੜϙΠϯλ → A ͕ഁغ͞Εͨ࣌ʹͦΕΛ஌Δํ๏͕ͳ͍ NG • shared_ptr → ॥؀ࢀরͯ͠͠·͍ɼӬԕʹࢀরΧ΢ϯτ ͕ 0 ʹͳΒͳ͘ͳΔʢϝϞϦϦʔΫʣ NG • weak_ptr → A ͕ഁغ͞Ε͍ͯΔ͔Ͳ͏͔Λ஌Δ͜ͱ͕ Ͱ͖ɼA Λॴ༗͍ͯ͠ͳ͍ͷͰ॥؀ࢀর΋ͳ͍ OK • ※໦ߏ଄Ͱ਌ͷΈ͕ࢠΛ shared_ptr Ͱࢦ͢ͱ͍ͬͨಛघͳ৚݅Ͱ͋Ε͹ࢠˠ਌͸ੜϙΠϯλͰ΋ྑ͍ Q

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Things to Remember • Ϧιʔε͕ແޮʹͳΔ͜ͱ͕͋Δ shared_ptr ͷΑ͏ͳϙΠϯλ͕΄͍࣌͠͸ std::weak_ptr Λ࢖͏ • weak_ptr ͷओͳϢʔεέʔε͸Ωϟογϡɼ Φϒβʔόɼ॥؀ࢀরͷճආͳͲ Q