Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
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
720
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
AIエージェントを活かすPM術 AI駆動開発の現場から
gyuta
0
240
All(?) About Point Sets
hole
0
280
TVerのWeb内製化 - 開発スピードと品質を両立させるまでの道のり
techtver
PRO
3
1.4k
FluorTracer / RayTracingCamp11
kugimasa
0
200
ローターアクトEクラブ アメリカンナイト:川端 柚菜 氏(Japan O.K. ローターアクトEクラブ 会長):2720 Japan O.K. ロータリーEクラブ2025年12月1日卓話
2720japanoke
0
700
大体よく分かるscala.collection.immutable.HashMap ~ Compressed Hash-Array Mapped Prefix-tree (CHAMP) ~
matsu_chara
1
210
TUIライブラリつくってみた / i-just-make-TUI-library
kazto
1
320
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
140
モダンJSフレームワークのビルドプロセス 〜なぜReactは503行、Svelteは12行なのか〜
fuuki12
0
200
Evolving NEWT’s TypeScript Backend for the AI-Driven Era
xpromx
0
280
Navigation 3: 적응형 UI를 위한 앱 탐색
fornewid
1
160
TypeScript 5.9 で使えるようになった import defer でパフォーマンス最適化を実現する
bicstone
1
1.1k
Featured
See All Featured
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
120
20k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
231
22k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
253
22k
Designing Experiences People Love
moore
142
24k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Principles of Awesome APIs and How to Build Them.
keavy
127
17k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
61k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
Site-Speed That Sticks
csswizardry
13
990
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.1k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
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