Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Effective Modern C++ Item19, Item20
Search
Linda_pp
April 22, 2015
Programming
1
730
Effective Modern C++ Item19, Item20
shared_ptr と weak_ptr の概要および内部的な話など.
Effective Modern C++ 読書会 4/22(水)
Linda_pp
April 22, 2015
Tweet
Share
More Decks by Linda_pp
See All by Linda_pp
actionlint の Linter 設計
rhysd
7
6.2k
ripgrep をライブラリとして使う
rhysd
0
630
port-monolith-to-wasm-for-chrome-extension
rhysd
0
510
Fuzzing Rust Text Editor
rhysd
1
3k
Vim compiled to WebAssembly
rhysd
5
2.3k
about-neovim-0.4.0-floating-window
rhysd
3
2.3k
reply.vim
rhysd
0
1.3k
Vim ported to WebAssembly (VimConf 2018)
rhysd
4
3.5k
go-selfupdate-github で ツールを自己アップデートする
rhysd
5
4.5k
Other Decks in Programming
See All in Programming
令和最新版Android Studioで化石デバイス向けアプリを作る
arkw
0
410
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
160
Claude Codeの「Compacting Conversation」を体感50%減! CLAUDE.md + 8 Skills で挑むコンテキスト管理術
kmurahama
0
180
AWS CDKの推しポイントN選
akihisaikeda
1
240
Rubyで鍛える仕組み化プロヂュース力
muryoimpl
0
130
TUIライブラリつくってみた / i-just-make-TUI-library
kazto
1
390
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
360
マスタデータ問題、マイクロサービスでどう解くか
kts
0
100
Socio-Technical Evolution: Growing an Architecture and Its Organization for Fast Flow
cer
PRO
0
340
Full-Cycle Reactivity in Angular: SignalStore mit Signal Forms und Resources
manfredsteyer
PRO
0
140
Canon EOS R50 V と R5 Mark II 購入でみえてきた最近のデジイチ VR180 事情、そして VR180 静止画に活路を見出すまで
karad
0
110
Context is King? 〜Verifiability時代とコンテキスト設計 / Beyond "Context is King"
rkaga
10
1.2k
Featured
See All Featured
It's Worth the Effort
3n
187
29k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.5k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
3.8k
Producing Creativity
orderedlist
PRO
348
40k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
70k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.1k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.6k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Site-Speed That Sticks
csswizardry
13
1k
How STYLIGHT went responsive
nonsquared
100
6k
Build The Right Thing And Hit Your Dates
maggiecrowley
38
3k
Transcript
Effective Modern C++ ಡॻձ Item 19, Item 20
@Linda_pp @rhysd झຯͰίϯύΠϥͱ͔ͭͬͯ͘·͢ɽ https://github.com/rhysd/Dachs
Item 19: ॴ༗ݖΛڞ༗͍ͨ͠Ϧ ιʔεͷཧʹ std::shared_ptr Λ͓͏
C++ ʹ͓͚ΔϝϞϦཧ Q.ʮͳΜͯݪ࢝తͳΜͩʂ1960ͷLisp ʹԿֶͳ ͔ͬͨͷ͔ʁϦιʔεਓؒͰͳ͘Ϛγϯ͕ཧ͖ͩ͢ʯ ! A.ʮϝϞϦ͚͕ͩϦιʔεͰͳ͍͠ɼϝϞϦ͕։์͞Ε ΔλΠϛϯά͕͔Βͳ͍ͷࠔΔɽԶୡී௨ͷ༧ଌͰ ͖ΔσετϥΫλ͕ྑ͍Μͩɽʯ Q
C++ ʹ͓͚ΔϝϞϦཧ ͦ͏͍ͬͯΓ GC ศརɽGCͱϝϞ Ϧखಈཧͷؒͷଘࡏ͕΄͍͠ɽ → std::shared_ptr Q
std::shared_ptr • Ϧιʔεͷॴ༗ݖΛࢀরΧϯτʹΑͬͯཧ͢ ΔϙΠϯλΫϥε • ϦιʔεΛॴ༗͍ͯ͠Δ shared_ptr ͷΛΧ ϯτ͓͖ͯ͠ɼΧϯτ͕ 0
ʹͳͬͨ࣌ʹϦ ιʔεͷσετϥΫλΛ࣮ߦ͢Δ • GC ͷΑ͏ʹࣗಈཧ͞ΕɼϦιʔεͷղ์λ Πϛϯά͕༧ଌՄೳͰ͋Δɽ Q
{ std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }
} std::shared_ptr 8JEHFU Q DPOTUSVDU DPOTUSVDU Q
{ std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }
} std::shared_ptr 8JEHFU Q Q DPOTUSVDU Q
{ std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }
} std::shared_ptr 8JEHFU Q Q EFTUSPZ Q
{ std::shared_ptr<int> p1{new Widget}; { auto p2 = p1; }
} std::shared_ptr 8JEHFU Q EFTUSPZ EFTUSPZ Q
ࢀরΧϯτͷίετ • shared_ptr ͷαΠζ → ੜϙΠϯλͷ2ഒʢ࣮ ࡍʹίϯτϩʔϧϒϩοΫʢޙड़ʣʣ • ϝϞϦϦιʔεಈతʹ֬อ͢Δඞཁ͕͋Δ •
ࢀরΧϯτͷૢ࡞ atomic Ͱ͋Δ (thread safety) Q
ࢀরΧϯτͷίετͷճආ • move ίϯετϥΫλΛ͏ͱࢀরΧϯτ มԽ͠ͳ͍ʢॴ༗ݖͷҠৡʣ ! ! • ʢ͜ͷଞʹ͠Ͱͳ͘ࢀর͠ʹ͢Δͳ ͲͰࢀরΧϯτͷ্ԼΛ͛Δʣ
Q std::shared_ptr<int> p1{new int}; ! // ࢀরΧϯτมԽͤͣɼp1 ʹ null ͕ೖ͞ΕΔ std::shared_ptr<int> p2{ std::move(p1) };
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
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
shared_ptr ͷαΠζ • unique_ptr ͱҟͳΓɼৗʹϙΠϯλ2ͭ • ͋ΕɼͰΧελϜσϦʔλͷαΠζ…ʁ • → ΧελϜσϦʔλͳͲผͷॴʹ֬อ
͞ΕΔʢޙड़ʣ Q
shared_ptr ͷ෦ߏ 1PJOUFSUP5 1PJOUFSUP$POUSPM#MPDL 50CKFDU 3FGFSFODF$PVOU 8FBL$PVOU 0UIFS%BUB DVTUPNEFMFUFS
BMMPDBUPS FUD TIBSFE@QUS5 $POUSPM#MPDL 3FTPVSDF Q
Control Block • ࢀরΧϯτऑࢀরΧϯτͳͲͷཧ ใΛ࣋ͭ • ཧରͷΦϒδΣΫτ͕ੜ͞Εͨ࣌ʹ1 ͚ͩੜ͞ΕΔ • Χϯτ͕྆ํ0ʹͳͬͨ࣌ʹഁغ͞ΕΔ
Q
Control Block ͷੜλΠϛϯά • std::make_shared() ͕ݺΕͨ࣌ • unique_ptr auto_ptr
Λݩʹ shared_ptr ͕ ͭ͘ΒΕͨ࣌ • ੜϙΠϯλΛݩʹ shared_ptr ͕ͭ͘ΒΕͨ࣌ Q $POUSPM#MPDLϦιʔεʹର͚ͯͭͩ͠ੜ ͠ͳ͚ΕͳΒͳ͍ʢϓϩάϥϚͷʣ
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
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
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
Control Block ͕ॏෳ͢Δྫ this ੜϙΠϯλͳͷͰɼprocess() ͕ݺΕ Δͨͼʹ৽͍͠ Control Block ͕ͭ͘ΒΕΔ
// ຊʹॻ͍ͯ·ͤΜ͕ɼ͜͏͍͏͜ͱ͕Γ͍ͨͣ ! std::shared_ptr<Widget> spw = std::make_shared(…); ! spw->process(); // NG ผͷ Control Block ͕ͭ͘ΒΕͯ͠·͏ Q
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()); }
std::enable_shared_from_this • ܧঝ͢Δͱϝϯόؔ shared_from_this() ͕͑ΔΑ͏ʹͳ ΔΫϥεςϯϓϨʔτ • shared_from_this() Control-Block
Λͭ͘Βͣʹ shared_ptr Λ࡞͢Δ • Control-Block ͕ແ͍߹ະఆٛಈ࡞ʢ͍͍ͨͯྫ֎ʣ • Control-Block ͕طʹ࡞͞Ε͍ͯΔඞཁ͕͋Δʢଞͷ shared_ptr ͕ͦͷΦϒδΣΫτΛࢦ͍ͯ͠Δඞཁ͕͋Δʣ Q
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
shared_ptr ͷίετ reasonable • Control Block ͷαΠζσϑΥϧτͰ3word • Control Block
࣮ʹԾؔΛ͍ͬͯΔ ͕ݺΕΔͷϦιʔε͕ഁغ͞ΕΔ1ճͷΈ • େͷϚγϯͰ atomic ͳૢ࡞1໋ྩͰ࣮ ߦͰ͖Δ Q
shared_ptr ͷίετ reasonable • एׯͷίετͱҾ͖͑ʹण໋ཧΛࣗಈͰ ߦ͑Δ • ͨͩ͠ॴ༗ݖΛڞ༗͢Δඞཁ͕ແ͍ͳΒ unique_ptr ͷ΄͏͕ྑ͍
• unique_ptr ඞཁʹԠͯ͡ shared_ptr ʹ ͤΔ Q
ྻͷཧ • C++14 ࣌Ͱ shared_ptr<T []> ߟྀ͞Ε͍ͯ ͳ͍ • std::vector
ͳͲͷίϯςφΛ͏͖ • C++17 Ͱྻͷαϙʔτ͕ఏҊ͞Ε͍ͯΔ ʢN3869, N3920, N3939ʣ • boost::shared_ptr ྻରԠࡁΈ Q
ྻͷཧ • ΧελϜσϦʔλΛͬͯ delete T[] ΛݺͿΑ ͏ʹͯ͠μϝ • operator[] ͕ແ͍
• جఈΫϥεͷ shared_ptr ͕ੜΫϥεͷΦ ϒδΣΫτΛࢦ͢ͱ͖ɼྻΛߟྀ͍ͯ͠ ͳ͍ Q
Things to Remember • shared_ptr ෳͷϙΠϯλʹڞ༗͞ΕΔϝϞϦҙͷϦ ιʔεͷण໋ཧΛߦ͑Δ • unique_ptr ͱൺͯαΠζ
atomic ͳૢ࡞ͳͲͷΦʔόʔϔο υ͕͋Δ • ϦιʔεͷഁغʹσϑΥϧτͰ delete ͕ΘΕΔ͕ɼΧελ ϜσϦʔλ͑ΔɽΧελϜσϦʔλ shared_ptr ͷܕʹӨ ڹΛ༩͑ͳ͍ • ੜϙΠϯλม͔Β shared_ptr Λͭ͘Δ͜ͱۃྗආ͚Δ͖ Q
Item20: ࢦ͢Ϧιʔε͕ແޮʹͳΓ ͏Δ shared_ptr ʹ std::weak_ptr Λ͓͏
ॴ༗ݖΛ࣋ͨͳ͍ϙΠϯλ • shared_ptr ͷΑ͏ʹಛఆͷϦιʔεΛࢦͤΔ ͕ɼॴ༗ݖ࣋ͨͳ͍ʢ=ࢀরΧϯτΛಈ͔ ͞ͳ͍ʣεϚʔτϙΠϯλ͕΄͍͠ • ͦͷϙΠϯλࢦ͍ͯ͠ΔϦιʔε͕ଞͷ shared_ptr ʹআ͞ΕΔՄೳੑ͕͋Δ
• ͦΕ std::weak_ptr ͰͰ͖ΔΑʂ Q
std::weak_ptr • dereference null νΣοΫͰ͖ͳ͍ • shared_ptr ͷঢ֨ͱࢦ͍ͯ͠ΔϦιʔε͕ ੜ͖͍ͯΔ͔Ͳ͏͔ͷνΣοΫ͕Ͱ͖Δ
• shared_ptr ͱҰॹʹ͏ʢ͍͍ͨͯ shared_ptr ͔Βੜ͞ΕΔʣ Q
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
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
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
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
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() ͷ΄͏͕Φεεϝ
Ϣʔεέʔε1: Ωϟογϡ Item18ʹैͬͯ Widget Λੜ͠ unique_ptr Ͱฦ͢ϑΝΫτϦؔΛ࡞ ! ! loadWidget()
ॲཧ͕ॏ͍ͷͰ Widget ʹৼ ΒΕͨ ID ΛͬͯΩϟογϡ͍ͨ͠ std::unique_ptr<const Widget> loadWidget(WidgetID id); Q
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: Ωϟογϡ
Ϣʔεέʔε1: Ωϟογϡ • ੜͨ͠Ϧιʔε͕ഁغ͞Ε͍ͯΔ͔Ͳ͏͔ΛΔඞ ཁ͕͋ΔͨΊɼweak_ptr ͰΩϟογϡ͢Δͷ͕ద • Ϧιʔεͷঢ়ଶΛΔͨΊʹΩϟογϡ͖ϑΝΫτ ϦؔͷΓ shared_ptr
ʹ͢Δඞཁ͕͋Δ (Control Block ͷ weak count) • expire ͨ͠ΩϟογϡͷআͳͲΛՃͯ͠ྑ͍ ͔͠Εͳ͍ Q
Ϣʔεέʔε2: Observer • observerʢsubject ͔Β௨Λड͚औΓԿ͔ॲཧΛ ߦ͏ʣ • subjectʢঢ়ଶΛ࣋ͪ observer ʹঢ়ଶͷมߋΛ௨
͢Δʣ • subject observer Λࢀর͢Δ͕ɼobserver ࢮ͵ ͜ͱ͕͋Δ → subject observer Λ weak_ptr Ͱ࣋ ͖ͭ Q
Ϣʔεέʔε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
Ϣʔεέʔε3: σʔλߏ ! ! ! B ͕ A Λࢦ࣌͢ɼԿΛ͑ྑ͍͔ #
" $ TIBSFE@QUS TIBSFE@QUS Q
??? ͷ෦ʹԿΛ͑ྑ͍͔ • ੜϙΠϯλ → A ͕ഁغ͞Εͨ࣌ʹͦΕΛΔํ๏͕ͳ͍ NG • shared_ptr
→ ॥ࢀরͯ͠͠·͍ɼӬԕʹࢀরΧϯτ ͕ 0 ʹͳΒͳ͘ͳΔʢϝϞϦϦʔΫʣ NG • weak_ptr → A ͕ഁغ͞Ε͍ͯΔ͔Ͳ͏͔ΛΔ͜ͱ͕ Ͱ͖ɼA Λॴ༗͍ͯ͠ͳ͍ͷͰ॥ࢀরͳ͍ OK • ※ߏͰͷΈ͕ࢠΛ shared_ptr Ͱࢦ͢ͱ͍ͬͨಛघͳ݅Ͱ͋ΕࢠˠੜϙΠϯλͰྑ͍ Q
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
Things to Remember • Ϧιʔε͕ແޮʹͳΔ͜ͱ͕͋Δ shared_ptr ͷΑ͏ͳϙΠϯλ͕΄͍࣌͠ std::weak_ptr Λ͏ •
weak_ptr ͷओͳϢʔεέʔεΩϟογϡɼ Φϒβʔόɼ॥ࢀরͷճආͳͲ Q