Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
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
700
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
6
5.9k
ripgrep をライブラリとして使う
rhysd
0
500
port-monolith-to-wasm-for-chrome-extension
rhysd
0
490
Fuzzing Rust Text Editor
rhysd
1
3k
Vim compiled to WebAssembly
rhysd
5
2.2k
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.4k
go-selfupdate-github で ツールを自己アップデートする
rhysd
5
4.4k
Other Decks in Programming
See All in Programming
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
890
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
280
AIエージェントはこう育てる - GitHub Copilot Agentとチームの共進化サイクル
koboriakira
0
480
Benchmark
sysong
0
280
第9回 情シス転職ミートアップ 株式会社IVRy(アイブリー)の紹介
ivry_presentationmaterials
1
260
AIプログラマーDevinは PHPerの夢を見るか?
shinyasaita
1
190
Select API from Kotlin Coroutine
jmatsu
1
220
VS Code Update for GitHub Copilot
74th
1
570
技術同人誌をMCP Serverにしてみた
74th
1
540
Quand Symfony, ApiPlatform, OpenAI et LangChain s'allient pour exploiter vos PDF : de la théorie à la production…
ahmedbhs123
0
120
Cursor AI Agentと伴走する アプリケーションの高速リプレイス
daisuketakeda
1
130
Deep Dive into ~/.claude/projects
hiragram
10
2.2k
Featured
See All Featured
The Cost Of JavaScript in 2023
addyosmani
51
8.5k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.6k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.8k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.9k
Site-Speed That Sticks
csswizardry
10
670
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
A Modern Web Designer's Workflow
chriscoyier
694
190k
Building an army of robots
kneath
306
45k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
124
52k
For a Future-Friendly Web
brad_frost
179
9.8k
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