ํฌ์ŠคํŠธ

CS โ€” smart pointer

CS โ€” smart pointer

๐Ÿ“• 04/24 โ€” C++ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ๋ชจ์˜๋ฉด์ ‘ ์ค€๋น„

๋‚ด์ผ ๋ชจ์˜๋ฉด์ ‘ ์ฃผ์ œ: โ€œC++ ์Šค๋งˆํŠธํฌ์ธํ„ฐ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”โ€ RAII โ†’ unique_ptr / shared_ptr / weak_ptr โ†’ ์ฐธ์กฐ ์นด์šดํŒ… โ†’ ์ˆœํ™˜ ์ฐธ์กฐ โ†’ virtual ์†Œ๋ฉธ์ž โ†’ vtable ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋‹ค๋ฆฌ


๋ชจ์˜๋ฉด์ ‘ ๋‹ต๋ณ€

์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋Š” ์›์‹œ ํฌ์ธํ„ฐ(raw pointer)๋ฅผ ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ RAII ์›์น™์œผ๋กœ ๋™์  ํ• ๋‹น ๋ฉ”๋ชจ๋ฆฌ์˜ ์ˆ˜๋ช…์„ ์ž๋™ ๊ด€๋ฆฌํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. C++11๋ถ€ํ„ฐ <memory> ํ—ค๋”์— unique_ptr, shared_ptr, weak_ptr ์„ธ ์ข…๋ฅ˜๊ฐ€ ํ‘œ์ค€์œผ๋กœ ์ œ๊ณต๋˜๋ฉฐ, ๊ฐ๊ฐ ๋‹ค๋ฅธ ์†Œ์œ ๊ถŒ ๋ชจ๋ธ์„ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.

unique_ptr์€ ๋‹จ๋… ์†Œ์œ ๊ถŒ์„ ๊ฐ€์ง€๋ฉฐ ๋ณต์‚ฌ ๋ถˆ๊ฐ€ยทmove๋งŒ ํ—ˆ์šฉํ•ด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ 0์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค. shared_ptr์€ ์ฐธ์กฐ ์นด์šดํŒ… ๊ธฐ๋ฐ˜ ๊ณต์œ  ์†Œ์œ ๊ถŒ์œผ๋กœ, ์ œ์–ด ๋ธ”๋ก(control block)์— strong count๋ฅผ ๋‘๊ณ  ์นด์šดํŠธ๊ฐ€ 0์ด ๋˜๋ฉด ์ž๋™์œผ๋กœ deleteํ•ฉ๋‹ˆ๋‹ค. weak_ptr์€ ์†Œ์œ ๊ถŒ ์—†๋Š” ์•ฝํ•œ ์ฐธ์กฐ๋กœ, shared_ptr ์‚ฌ์ด์˜ ์ˆœํ™˜ ์ฐธ์กฐ(circular reference) ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์“ฐ์ž…๋‹ˆ๋‹ค.

์ƒ์„ฑ ์‹œ์—๋Š” new ์ง์ ‘ ํ˜ธ์ถœ๋ณด๋‹ค make_unique/make_shared ํŒฉํ† ๋ฆฌ๋ฅผ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์™ธ ์•ˆ์ „์„ฑ์ด ๋ณด์žฅ๋˜๊ณ , make_shared๋Š” ๊ฐ์ฒด์™€ ์ œ์–ด ๋ธ”๋ก์„ ๋‹จ์ผ ํž™ ํ• ๋‹น์œผ๋กœ ๋ฌถ์–ด ์บ์‹œ ์ง€์—ญ์„ฑ๊ณผ ์„ฑ๋Šฅ์ด ์ข‹์•„์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ unique_ptr<Base> ๋‚˜ shared_ptr<Base>๋กœ ํŒŒ์ƒ ๊ฐ์ฒด๋ฅผ ๋‹ด์„ ๋•Œ๋Š” ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์— virtual ์†Œ๋ฉธ์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ์„ ์–ธ๋˜์–ด ์žˆ์–ด์•ผ ํŒŒ์ƒ ์†Œ๋ฉธ์ž๊นŒ์ง€ ์˜ฌ๋ฐ”๋ฅธ ์ฒด์ธ ํ˜ธ์ถœ์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค.

โ€œnew๋กœ ๋งŒ๋“  raw pointer๋ฅผ shared_ptr์— ๋„˜๊ธฐ๋ฉด ์„ธ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ์งธ, ํ•จ์ˆ˜ ์ธ์ž ํ‰๊ฐ€ ์ˆœ์„œ์— ๋”ฐ๋ผ ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋ˆ„์ˆ˜๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋‘˜์งธ, ๊ฐ์ฒด์™€ ์ œ์–ด ๋ธ”๋ก์ด ๋ณ„๋„๋กœ ํž™ ํ• ๋‹น๋ผ ์บ์‹œ ์ง€์—ญ์„ฑ์ด ๋‚˜์ฉ๋‹ˆ๋‹ค. ์…‹์งธ, ๊ฐ™์€ raw pointer๋ฅผ ๋‘ shared_ptr์— ๋„˜๊ธฐ๋ฉด ์ œ์–ด
โ–Ž ๋ธ”๋ก์ด ๋”ฐ๋กœ ์ƒ๊ฒจ ์ด์ค‘ ํ•ด์ œ UB๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ธฐ๋ณธ์€ make_shared๋ฅผ ์“ฐ๊ณ , ์ปค์Šคํ…€ deleter๋‚˜ ํฐ ๊ฐ์ฒด + weak_ptr ์žฅ๊ธฐ ๋ณด๊ด€ ๊ฐ™์€ ํŠน์ˆ˜ ์ผ€์ด์Šค์—์„œ๋งŒ new๋ฅผ ์”๋‹ˆ๋‹ค.โ€

ํ•ต์‹ฌ ๊ฐœ๋…

  • ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ (Smart Pointer) โ€” ์›์‹œ ํฌ์ธํ„ฐ๋ฅผ RAII๋กœ ๊ฐ์‹ผ ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค. ์†Œ๋ฉธ์ž์—์„œ ์ž๋™ delete
  • unique_ptr โ€” ๋‹จ๋… ์†Œ์œ ๊ถŒ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ. ๋ณต์‚ฌ ๋ถˆ๊ฐ€, move๋งŒ ํ—ˆ์šฉ. ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๋กœ (sizeof = ํฌ์ธํ„ฐ 1๊ฐœ)
  • shared_ptr โ€” ์ฐธ์กฐ ์นด์šดํŒ… ๊ณต์œ  ์†Œ์œ ๊ถŒ. ์ œ์–ด ๋ธ”๋ก(control block)์— strong/weak count ๋ณด๊ด€
  • weak_ptr โ€” ์†Œ์œ ๊ถŒ ์—†๋Š” ์•ฝํ•œ ์ฐธ์กฐ. shared_ptr์˜ strong count ์ฆ๊ฐ€ X, weak count๋งŒ ์ฆ๊ฐ€
  • ์ œ์–ด ๋ธ”๋ก (Control Block) โ€” shared_ptr์ด ๊ณต์œ ํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ. strong count, weak count, deleter ํฌํ•จ
  • ์ฐธ์กฐ ์นด์šดํŒ… (Reference Counting) โ€” ์›์ž์ (atomic) ์นด์šดํŠธ ์ฆ๊ฐ. 0์ด ๋˜๋ฉด ๊ฐ์ฒด delete, strong+weak ๋ชจ๋‘ 0์ด๋ฉด ์ œ์–ด ๋ธ”๋ก๊นŒ์ง€ ํ•ด์ œ
  • ์ˆœํ™˜ ์ฐธ์กฐ (Circular Reference) โ€” shared_ptr๋ผ๋ฆฌ ์„œ๋กœ ์ฐธ์กฐํ•ด ์นด์šดํŠธ๊ฐ€ ์ ˆ๋Œ€ 0์ด ๋˜์ง€ ์•Š๋Š” ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํŒจํ„ด
  • make_unique / make_shared โ€” C++14/11 ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜. ์˜ˆ์™ธ ์•ˆ์ „์„ฑ ๋ณด์žฅ, make_shared๋Š” ๋‹จ์ผ ํž™ ํ• ๋‹น์œผ๋กœ ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • std::move / ์†Œ์œ ๊ถŒ ์ด์ „ โ€” unique_ptr์„ ํ•จ์ˆ˜ ์ธ์žยท๋ฐ˜ํ™˜์œผ๋กœ ๋„˜๊ธธ ๋•Œ ์‚ฌ์šฉ. ์›๋ณธ์€ nullptr์ด ๋จ
  • deleter โ€” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ํ•ด์ œ ์‹œ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜. ๋ฐฐ์—ด, ํŒŒ์ผ ํ•ธ๋“ค, ์ปค์Šคํ…€ ํ•ด์ œ ๋กœ์ง์— ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅ
  • enable_shared_from_this โ€” ๊ฐ์ฒด ๋‚ด๋ถ€์—์„œ ์ž๊ธฐ ์ž์‹ ์„ ๊ฐ€๋ฆฌํ‚ค๋Š” shared_ptr์„ ์–ป์„ ๋•Œ ์‚ฌ์šฉ (this๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ์‹ธ๋ฉด UB)
  • RAII ์—ฐ๊ฒฐ โ€” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ = RAII์˜ ๊ฐ€์žฅ ๋Œ€ํ‘œ์  ์ ์šฉ. ์Šคํƒ ๊ฐ์ฒด ์ˆ˜๋ช…์— ํž™ ์ž์› ์ˆ˜๋ช…์„ ๋ฌถ์Œ
  • virtual ์†Œ๋ฉธ์ž ์—ฐ๊ฒฐ โ€” unique_ptr<Base>/shared_ptr<Base>์—์„œ ํŒŒ์ƒ ๊ฐ์ฒด ์†Œ๋ฉธ ์‹œ ํ•„์ˆ˜ ์กฐ๊ฑด

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. unique_ptr โ€” ๋‹จ๋… ์†Œ์œ 
  3. shared_ptr โ€” ๊ณต์œ  ์†Œ์œ  + ์ฐธ์กฐ ์นด์šดํŒ…
  4. weak_ptr โ€” ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ
  5. make_unique vs make_shared vs new
  6. RAII ๋ฐ virtual ์†Œ๋ฉธ์ž์™€์˜ ์—ฐ๊ฒฐ
  7. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ
  8. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ

1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ

์Šค๋งˆํŠธ ํฌ์ธํ„ฐ 3์ข… 30์ดˆ

1
2
3
4
unique_ptr  โ€” ๋‹จ๋… ์†Œ์œ . ๋ณต์‚ฌ ๋ถˆ๊ฐ€, move๋งŒ ํ—ˆ์šฉ. ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๋กœ.
shared_ptr  โ€” ๊ณต์œ  ์†Œ์œ . ์ฐธ์กฐ ์นด์šดํŒ…. ์ œ์–ด ๋ธ”๋ก ์˜ค๋ฒ„ํ—ค๋“œ ์žˆ์Œ.
weak_ptr    โ€” ์†Œ์œ ๊ถŒ ์—†์Œ. shared_ptr ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ์šฉ.
๊ณตํ†ต        โ€” RAII๋กœ delete ์ž๋™ํ™” โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€.

์ฐธ์กฐ ์นด์šดํŒ… 30์ดˆ

1
2
3
4
5
shared_ptr ๋ณต์‚ฌ      โ†’ strong count++ (atomic)
shared_ptr ์†Œ๋ฉธ      โ†’ strong count-- (atomic)
strong count == 0    โ†’ ๊ฐ์ฒด delete
strong + weak == 0   โ†’ ์ œ์–ด ๋ธ”๋ก๊นŒ์ง€ ํ•ด์ œ
์ฃผ์˜: ์นด์šดํŠธ ์กฐ์ž‘์€ atomic โ†’ thread-safe, ๋Œ€์‹  ๋น„์šฉ ์žˆ์Œ

์ˆœํ™˜ ์ฐธ์กฐ 30์ดˆ

1
2
3
4
5
shared_ptr<A> โ†’ shared_ptr<B> โ†’ shared_ptr<A> ๋กœ ๋ฃจํ”„ ํ˜•์„ฑ
โ†’ ์„œ๋กœ ์ฐธ์กฐํ•ด strong count๊ฐ€ ์ ˆ๋Œ€ 0์ด ์•ˆ ๋จ โ†’ ์˜๊ตฌ ๋ˆ„์ˆ˜

ํ•ด๊ฒฐ: ํ•œ์ชฝ์„ weak_ptr๋กœ ๊ต์ฒด
โ†’ ๋ถ€๋ชจ๋Š” shared_ptr(์†Œ์œ ), ์ž์‹์€ weak_ptr(๊ด€์ฐฐ)

๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๋งต

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
์Šค๋งˆํŠธ ํฌ์ธํ„ฐ
โ”œโ”€โ”€ unique_ptr
โ”‚   โ”œโ”€โ”€ ๋ณต์‚ฌ ๋ถˆ๊ฐ€, move semantics โ†’ std::move
โ”‚   โ””โ”€โ”€ ์ปค์Šคํ…€ deleter (๋ฐฐ์—ด, ํŒŒ์ผ ํ•ธ๋“ค)
โ”œโ”€โ”€ shared_ptr
โ”‚   โ”œโ”€โ”€ ์ฐธ์กฐ ์นด์šดํŒ… โ†’ atomic ๋น„์šฉ
โ”‚   โ”œโ”€โ”€ ์ œ์–ด ๋ธ”๋ก ๊ตฌ์กฐ
โ”‚   โ””โ”€โ”€ ์ˆœํ™˜ ์ฐธ์กฐ โ†’ weak_ptr ํ•ด๊ฒฐ โ˜…
โ”œโ”€โ”€ weak_ptr
โ”‚   โ””โ”€โ”€ lock() โ†’ ๋งŒ๋ฃŒ ์•ˆ ๋์œผ๋ฉด shared_ptr ์Šน๊ฒฉ
โ”œโ”€โ”€ make_unique / make_shared
โ”‚   โ”œโ”€โ”€ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ
โ”‚   โ””โ”€โ”€ ๋‹จ์ผ ํž™ ํ• ๋‹น (make_shared)
โ””โ”€โ”€ RAII โ†’ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ (์ „๋‚  ์ฃผ์ œ ๋ณต์Šต)
    โ””โ”€โ”€ virtual ์†Œ๋ฉธ์ž ํ•„์ˆ˜ (โ˜… ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ!)
        โ””โ”€โ”€ vtable โ†’ ๋™์  ๋””์ŠคํŒจ์น˜ (์ „์ „๋‚  ์ฃผ์ œ ํšŒ๊ท€)

2. unique_ptr โ€” ๋‹จ๋… ์†Œ์œ 

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

unique_ptr์€ ๊ฐ์ฒด๋ฅผ ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ํฌ์ธํ„ฐ๋งŒ ์†Œ์œ ํ•˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค. ๋ณต์‚ฌ๋Š” ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  std::move๋กœ ์†Œ์œ ๊ถŒ์„ ์ด์ „ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

1
2
3
4
5
6
7
8
9
10
11
12
#include <memory>

// ์ƒ์„ฑ (๊ถŒ์žฅ: make_unique)
std::unique_ptr<int> p = std::make_unique<int>(42);

// ์—ญ์ฐธ์กฐ, ๋ฉค๋ฒ„ ์ ‘๊ทผ
std::cout << *p << std::endl;    // 42
std::cout << p.get() << std::endl;  // ์›์‹œ ํฌ์ธํ„ฐ ์กฐํšŒ (์†Œ์œ ๊ถŒ ์œ ์ง€)

// ์†Œ์œ ๊ถŒ ํ•ด์ œ
p.reset();                        // delete ํ›„ nullptr
std::unique_ptr<int> q = std::move(p);  // ์†Œ์œ ๊ถŒ ์ด์ „ โ†’ p == nullptr

๋ณต์‚ฌ ๋ถˆ๊ฐ€, move๋งŒ ํ—ˆ์šฉ

1
2
3
4
5
std::unique_ptr<int> a = std::make_unique<int>(10);

// std::unique_ptr<int> b = a;         // โŒ ์ปดํŒŒ์ผ ์—๋Ÿฌ (๋ณต์‚ฌ ์ƒ์„ฑ์ž = delete)
std::unique_ptr<int> b = std::move(a); // โœ… ์†Œ์œ ๊ถŒ ์ด์ „
// ์ด์ œ a๋Š” nullptr, b๊ฐ€ ๊ฐ์ฒด ์†Œ์œ 

ํ•จ์ˆ˜ ์ธ์žยท๋ฐ˜ํ™˜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ์†Œ์œ ๊ถŒ ์ด์ „ ๋ฐ›๊ธฐ
void Consume(std::unique_ptr<Widget> w) {
    w->DoWork();
}  // w ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ โ†’ delete

// ์†Œ์œ ๊ถŒ์€ ์œ ์ง€, ์ฐธ์กฐ๋งŒ
void Use(Widget* w) { w->DoWork(); }
void Use(Widget& w) { w.DoWork(); }

// ์†Œ์œ ๊ถŒ ๋ฐ˜ํ™˜
std::unique_ptr<Widget> Create() {
    return std::make_unique<Widget>();   // RVO/move๋กœ ๋ฐ˜ํ™˜
}

auto p = Create();
Consume(std::move(p));   // ์†Œ์œ ๊ถŒ Consume์— ์ด์ „

๋ฐฐ์—ด ํŠนํ™” ๋ฒ„์ „

1
2
3
4
std::unique_ptr<int[]> arr = std::make_unique<int[]>(100);
arr[0] = 1;
arr[99] = 42;
// ์†Œ๋ฉธ ์‹œ delete[] ์ž๋™ ํ˜ธ์ถœ

์ปค์Šคํ…€ deleter

1
2
3
4
// ํŒŒ์ผ ํ•ธ๋“ค ๊ด€๋ฆฌ
auto fileDeleter = [](FILE* f) { if (f) fclose(f); };
std::unique_ptr<FILE, decltype(fileDeleter)> file(fopen("data.txt", "r"), fileDeleter);
// ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ โ†’ fclose ์ž๋™ ํ˜ธ์ถœ

์˜ค๋ฒ„ํ—ค๋“œ

  • sizeof(unique_ptr<T>) == sizeof(T*) (๊ธฐ๋ณธ deleter์ผ ๋•Œ)
  • ๋Ÿฐํƒ€์ž„ ๋น„์šฉ ์—†์Œ โ€” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ตœ์ ํ™”ํ•˜๋ฉด raw pointer์™€ ๊ฑฐ์˜ ๋™์ผํ•œ ์„ฑ๋Šฅ
  • ๊ถŒ์žฅ ๊ธฐ๋ณธ๊ฐ’: ์†Œ์œ ๊ถŒ ๊ณต์œ ๊ฐ€ ํ•„์š” ์—†๋‹ค๋ฉด ํ•ญ์ƒ unique_ptr ์‚ฌ์šฉ

3. shared_ptr โ€” ๊ณต์œ  ์†Œ์œ  + ์ฐธ์กฐ ์นด์šดํŒ…

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

shared_ptr์€ ์—ฌ๋Ÿฌ ํฌ์ธํ„ฐ๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๊ณต์œ  ์†Œ์œ ํ•˜๋„๋ก ํ•˜๋Š” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์ด๋ฉฐ, ์ฐธ์กฐ ์นด์šดํŒ…์œผ๋กœ ๋งˆ์ง€๋ง‰ ์†Œ์œ ์ž๊ฐ€ ์‚ฌ๋ผ์งˆ ๋•Œ ๊ฐ์ฒด๋ฅผ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

1
2
3
4
5
6
std::shared_ptr<Widget> p1 = std::make_shared<Widget>();  // strong=1
{
    std::shared_ptr<Widget> p2 = p1;   // strong=2
    p2->DoWork();
}  // p2 ์†Œ๋ฉธ โ†’ strong=1
// p1 ์†Œ๋ฉธ โ†’ strong=0 โ†’ Widget delete

์ œ์–ด ๋ธ”๋ก (Control Block) ๊ตฌ์กฐ

1
2
3
4
5
6
7
8
9
10
shared_ptr ๊ฐ์ฒด                  ์ œ์–ด ๋ธ”๋ก (ํž™)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ T* ptr          โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚ atomic strong_count  โ”‚
โ”‚ ControlBlock* cbโ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚   โ”‚ atomic weak_count    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜        โ”‚ โ””โ”€โ†’ โ”‚ T* managed_object    โ”‚โ”€โ”€โ”€โ†’ ์‹ค์ œ ๊ฐ์ฒด
                           โ””โ”€โ”€โ”€โ†’ โ”‚ Deleter              โ”‚
                                 โ”‚ Allocator            โ”‚
                                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

shared_ptr: 16 bytes (ptr 8 + control block ptr 8)  โ† unique_ptr์˜ 2๋ฐฐ ํฌ๊ธฐ

์ฐธ์กฐ ์นด์šดํŒ… ๋™์ž‘

1
2
3
4
5
6
7
8
9
std::shared_ptr<int> a = std::make_shared<int>(42);  // strong=1, weak=0

std::shared_ptr<int> b = a;     // strong=2 (atomic++)
std::shared_ptr<int> c = b;     // strong=3 (atomic++)

b.reset();                       // strong=2 (atomic--)
c = nullptr;                     // strong=1 (atomic--)

// a๋งŒ ๋‚จ์Œ. a ์†Œ๋ฉธ ์‹œ strong=0 โ†’ int ๊ฐ์ฒด delete, ์ œ์–ด ๋ธ”๋ก๋„ ํ•ด์ œ

์™œ atomic ์ธ๊ฐ€?

  • shared_ptr์€ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ๋™์‹œ ๋ณต์‚ฌ/์†Œ๋ฉธ๋  ์ˆ˜ ์žˆ์Œ
  • ์นด์šดํŠธ ์ฆ๊ฐ์ด ์›์ž์ ์ด์ง€ ์•Š์œผ๋ฉด data race โ†’ ์ด์ค‘ ํ•ด์ œ ๋˜๋Š” ๋ˆ„์ˆ˜
  • ์ฃผ์˜: ์นด์šดํŠธ๋Š” atomic์ด์ง€๋งŒ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด ์ž์ฒด๋Š” thread-safe ์•„๋‹˜
  • atomic ์—ฐ์‚ฐ์€ ์ผ๋ฐ˜ ๋ณ€์ˆ˜๋ณด๋‹ค ์ˆ˜ ๋ฐฐ ๋А๋ฆฌ๋ฏ€๋กœ shared_ptr์€ ๊ณต์งœ๊ฐ€ ์•„๋‹˜

์ปค์Šคํ…€ deleter

1
2
3
4
std::shared_ptr<FILE> file(fopen("data.txt", "r"), [](FILE* f) {
    if (f) fclose(f);
});
// ๊ณต์œ  ์†Œ์œ  + ์ž๋™ fclose

enable_shared_from_this โ€” this๋ฅผ shared_ptr๋กœ ๊ฐ์‹ธ๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// โŒ ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• โ€” ์ด์ค‘ ์ œ์–ด ๋ธ”๋ก ์ƒ์„ฑ โ†’ ์ด์ค‘ ํ•ด์ œ UB
class Widget {
public:
    std::shared_ptr<Widget> GetSelf() {
        return std::shared_ptr<Widget>(this);  // ์œ„ํ—˜!
    }
};

// โœ… ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• โ€” enable_shared_from_this ์ƒ์†
class Widget : public std::enable_shared_from_this<Widget> {
public:
    std::shared_ptr<Widget> GetSelf() {
        return shared_from_this();   // ๊ธฐ์กด ์ œ์–ด ๋ธ”๋ก ์žฌ์‚ฌ์šฉ
    }
};

auto w = std::make_shared<Widget>();
auto self = w->GetSelf();   // ๊ฐ™์€ ์ œ์–ด ๋ธ”๋ก ๊ณต์œ , strong=2

4. weak_ptr โ€” ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

weak_ptr์€ shared_ptr์ด ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์†Œ์œ ๊ถŒ ์—†์ด ๊ด€์ฐฐํ•˜๋Š” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋กœ, ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ์™€ ๋Œ•๊ธ€๋ง ๊ฐ์ง€์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Node {
    std::shared_ptr<Node> next;   // ๋ฌธ์ œ!
    ~Node() { std::cout << "Node ํ•ด์ œ\n"; }
};

{
    auto a = std::make_shared<Node>();   // a: strong=1
    auto b = std::make_shared<Node>();   // b: strong=1

    a->next = b;    // b: strong=2
    b->next = a;    // a: strong=2
}   // ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ
// a ์†Œ๋ฉธ โ†’ a: strong=1 (b->next๊ฐ€ ์—ฌ์ „ํžˆ a๋ฅผ ์žก๊ณ  ์žˆ์Œ)
// b ์†Œ๋ฉธ โ†’ b: strong=1 (a->next๊ฐ€ ์—ฌ์ „ํžˆ b๋ฅผ ์žก๊ณ  ์žˆ์Œ)
// ๋‘˜ ๋‹ค strong=1 โ†’ delete ์•ˆ ๋จ โ†’ ์˜๊ตฌ ๋ˆ„์ˆ˜!
// "Node ํ•ด์ œ" ํ•œ ๋ฒˆ๋„ ์ถœ๋ ฅ ์•ˆ ๋จ

ํ•ด๊ฒฐ: ํ•œ์ชฝ์„ weak_ptr๋กœ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Node {
    std::weak_ptr<Node> next;   // ์†Œ์œ ๊ถŒ ์—†์Œ โ†’ strong count ์ฆ๊ฐ€ ์•ˆ ํ•จ
    ~Node() { std::cout << "Node ํ•ด์ œ\n"; }
};

{
    auto a = std::make_shared<Node>();
    auto b = std::make_shared<Node>();

    a->next = b;    // b: strong=1, weak=1 (strong ๋ณ€๋™ ์—†์Œ!)
    b->next = a;    // a: strong=1, weak=1
}
// a ์†Œ๋ฉธ โ†’ a: strong=0 โ†’ delete โ†’ weak count๋งŒ ๋‚จ์Œ
// b ์†Œ๋ฉธ โ†’ b: strong=0 โ†’ delete
// "Node ํ•ด์ œ" ๋‘ ๋ฒˆ ์ถœ๋ ฅ ์ •์ƒ

์‹ค์ „ ํŒจํ„ด: ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„

1
2
3
4
5
6
7
struct Parent {
    std::vector<std::shared_ptr<Child>> children;  // ๋ถ€๋ชจ๊ฐ€ ์ž์‹ ์†Œ์œ 
};

struct Child {
    std::weak_ptr<Parent> parent;                  // ์ž์‹์€ ๋ถ€๋ชจ ๊ด€์ฐฐ๋งŒ
};

weak_ptr ์‚ฌ์šฉ โ€” lock()์œผ๋กœ ์Šน๊ฒฉ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
std::weak_ptr<Widget> wp = GetGlobalWidget();

// ์ง์ ‘ ์—ญ์ฐธ์กฐ ๋ถˆ๊ฐ€ โ€” ๋ฐ˜๋“œ์‹œ lock()์œผ๋กœ shared_ptr ์–ป๊ธฐ
if (std::shared_ptr<Widget> sp = wp.lock()) {
    sp->DoWork();    // ๊ฐ์ฒด๊ฐ€ ์‚ด์•„์žˆ์Œ โ†’ ์•ˆ์ „
} else {
    // ์ด๋ฏธ ํ•ด์ œ๋จ โ†’ ์‚ฌ์šฉ ๋ถˆ๊ฐ€
}

// expired() ์ฒดํฌ
if (!wp.expired()) {
    auto sp = wp.lock();
    // ...
}

weak_ptr ์˜ค๋ฒ„ํ—ค๋“œ

  • sizeof(weak_ptr<T>) == sizeof(shared_ptr<T>) (ํฌ์ธํ„ฐ 2๊ฐœ)
  • weak_count๊ฐ€ 0์ด ์•„๋‹ˆ๋ฉด ์ œ์–ด ๋ธ”๋ก์€ ๊ณ„์† ๋‚จ์•„ ์žˆ์Œ
  • lock()์€ atomic ์—ฐ์‚ฐ โ€” ๋น„์šฉ ์žˆ์Œ

5. make_unique vs make_shared vs new

ํ•ต์‹ฌ ํ•œ ๋ฌธ์žฅ

make_* ํŒฉํ† ๋ฆฌ๋Š” ์˜ˆ์™ธ ์•ˆ์ „์„ฑ๊ณผ ๋‹จ์ผ ํž™ ํ• ๋‹น์˜ ์žฅ์ ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ, ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด new๋ณด๋‹ค ํ•ญ์ƒ ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์™ธ ์•ˆ์ „์„ฑ (Exception Safety)

1
2
3
4
5
6
7
8
// โŒ ์œ„ํ—˜ํ•œ ํŒจํ„ด โ€” ํ‰๊ฐ€ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋ˆ„์ˆ˜ ๊ฐ€๋Šฅ
Process(std::shared_ptr<A>(new A()), MayThrow());
// ํ‰๊ฐ€ ์ˆœ์„œ๊ฐ€ [new A, MayThrow(), shared_ptr ์ƒ์„ฑ] ์ด๋ฉด
// MayThrow()๊ฐ€ ๋˜์งˆ ๋•Œ A ๊ฐ์ฒด ๋ˆ„์ˆ˜!

// โœ… ์•ˆ์ „ํ•œ ํŒจํ„ด
Process(std::make_shared<A>(), MayThrow());
// make_shared๋Š” ์›์ž์ ์œผ๋กœ ์ƒ์„ฑ โ†’ ๋ˆ„์ˆ˜ ์—†์Œ

make_shared์˜ ๋‹จ์ผ ํž™ ํ• ๋‹น

1
2
3
4
5
6
7
8
new ์ง์ ‘ ์‚ฌ์šฉ:
  [ ํž™1: A ๊ฐ์ฒด          ]   โ† new A()
  [ ํž™2: ์ œ์–ด ๋ธ”๋ก        ]   โ† shared_ptr ์ƒ์„ฑ ์‹œ ๋ณ„๋„ ํ• ๋‹น
  ์ด 2ํšŒ ํ• ๋‹น, ์บ์‹œ ์ง€์—ญ์„ฑ ๋‚˜์จ

make_shared ์‚ฌ์šฉ:
  [ ํž™1: ์ œ์–ด ๋ธ”๋ก + A ๊ฐ์ฒด ]  โ† ๋‹จ์ผ ๋ธ”๋ก์œผ๋กœ ๋ฌถ์–ด ํ• ๋‹น
  ์ด 1ํšŒ ํ• ๋‹น, ์บ์‹œ ์ง€์—ญ์„ฑ ์ข‹์Œ
1
2
3
4
5
// 2ํšŒ ํ• ๋‹น
std::shared_ptr<Widget> p1(new Widget());

// 1ํšŒ ํ• ๋‹น โ†’ ๋” ๋น ๋ฆ„
std::shared_ptr<Widget> p2 = std::make_shared<Widget>();

make_shared ๋‹จ์  / ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผ ํ•  ๋•Œ

1
2
3
4
5
6
7
// 1) ์ปค์Šคํ…€ deleter ์ง€์ • ๋ถˆ๊ฐ€ โ€” ๋ฐ˜๋“œ์‹œ new ์‚ฌ์šฉ
std::shared_ptr<FILE> f(fopen("x", "r"), [](FILE* f){ fclose(f); });

// 2) ํฐ ๊ฐ์ฒด + weak_ptr ์žฅ๊ธฐ ๋ณด๊ด€ ์‹œ ๋ฌธ์ œ
// make_shared๋Š” ๊ฐ์ฒด์™€ ์ œ์–ด ๋ธ”๋ก์„ ํ•œ ๋ธ”๋ก์— ๋ฌถ์Œ
// โ†’ ๊ฐ์ฒด๋Š” delete ๋˜์–ด๋„, weak_count > 0 ์ด๋ฉด ๋ธ”๋ก ์ „์ฒด๊ฐ€ ๋‚จ์Œ
// โ†’ ํฐ ๊ฐ์ฒด์˜ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ weak_ptr ์‚ด์•„์žˆ๋Š” ๋™์•ˆ ํ•ด์ œ ์•ˆ ๋จ

๋น„๊ต ํ‘œ

ย new T()make_unique<T>()make_shared<T>()
๋ฐ˜ํ™˜ ํƒ€์ž…T* (raw)unique_ptr<T>shared_ptr<T>
์˜ˆ์™ธ ์•ˆ์ „์„ฑ์ˆ˜๋™ ๊ด€๋ฆฌ ํ•„์š”์ž๋™์ž๋™
ํž™ ํ• ๋‹น ํšŸ์ˆ˜1ํšŒ (๊ฐ์ฒด๋งŒ)1ํšŒ (๊ฐ์ฒด๋งŒ)1ํšŒ (๊ฐ์ฒด+์ œ์–ด๋ธ”๋ก)
์ปค์Šคํ…€ deleterN/A๊ฐ€๋Šฅ๋ถˆ๊ฐ€
์™„์ „ ํƒ€์ž… ํ•„์š”ํ•„์š”ํ˜ธ์ถœ ์‹œ์  ํ•„์š”ํ˜ธ์ถœ ์‹œ์  ํ•„์š”
๊ถŒ์žฅ ์—ฌ๋ถ€์ตœํ›„์˜ ์ˆ˜๋‹จ๊ธฐ๋ณธ๊ฐ’๊ณต์œ  ํ•„์š” ์‹œ ๊ธฐ๋ณธ๊ฐ’

6. RAII ๋ฐ virtual ์†Œ๋ฉธ์ž์™€์˜ ์—ฐ๊ฒฐ

์Šค๋งˆํŠธ ํฌ์ธํ„ฐ = RAII์˜ ๋Œ€ํ‘œ ์‚ฌ๋ก€

1
2
3
4
5
6
7
8
9
10
11
12
// RAII ๋ฏธ์ ์šฉ โ€” ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋ˆ„์ˆ˜
void BadFunction() {
    Widget* w = new Widget();
    MayThrow();      // ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ โ†“ ์‹คํ–‰ ์•ˆ ๋จ
    delete w;        // ๋ˆ„์ˆ˜!
}

// RAII ์ ์šฉ โ€” ์˜ˆ์™ธ ์•ˆ์ „ ๋ณด์žฅ
void GoodFunction() {
    auto w = std::make_unique<Widget>();
    MayThrow();      // ์˜ˆ์™ธ ๋ฐœ์ƒํ•ด๋„ OK
}  // ์Šคํƒ ํ•ด์ œ ์‹œ w ์†Œ๋ฉธ์ž๊ฐ€ delete ๋ณด์žฅ

virtual ์†Œ๋ฉธ์ž ํ•„์ˆ˜ โ€” ์™œ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Base {
public:
    ~Base() { std::cout << "Base ํ•ด์ œ\n"; }   // virtual ์•„๋‹˜!
};

class Derived : public Base {
    int* data = new int[1000];
public:
    ~Derived() {
        delete[] data;
        std::cout << "Derived ํ•ด์ œ\n";
    }
};

// unique_ptr<Base>๋กœ Derived ๊ฐ์ฒด ๊ด€๋ฆฌ
std::unique_ptr<Base> p = std::make_unique<Derived>();
// p ์†Œ๋ฉธ ์‹œ:
//   unique_ptr ์†Œ๋ฉธ์ž โ†’ delete (Base*)
//   โ†’ Base::~Base() ๋งŒ ํ˜ธ์ถœ (virtual ์•„๋‹ˆ๋ฏ€๋กœ ์ •์  ๋ฐ”์ธ๋”ฉ)
//   โ†’ Derived::~Derived() ๋ฏธํ˜ธ์ถœ
//   โ†’ data 4000 bytes ๋ˆ„์ˆ˜!

ํ•ด๊ฒฐ: virtual ์†Œ๋ฉธ์ž

1
2
3
4
5
6
7
8
9
10
11
class Base {
public:
    virtual ~Base() = default;   // virtual ์ถ”๊ฐ€!
};

std::unique_ptr<Base> p = std::make_unique<Derived>();
// p ์†Œ๋ฉธ ์‹œ:
//   delete (Base*)
//   โ†’ vptr โ†’ Derived vtable โ†’ Derived::~Derived() ํ˜ธ์ถœ
//   โ†’ ์ž๋™์œผ๋กœ Base::~Base() ์ฒด์ธ ํ˜ธ์ถœ
//   โ†’ ๋ฉ”๋ชจ๋ฆฌ ์ •์ƒ ํ•ด์ œ

shared_ptr์€ ์™œ virtual ์†Œ๋ฉธ์ž ์—†์ด๋„ ๊ฐ€๋” ๋™์ž‘ํ•˜๋‚˜?

shared_ptr์€ ํƒ€์ž… ์†Œ๊ฑฐ(type erasure)๋œ deleter๋ฅผ ์ œ์–ด ๋ธ”๋ก์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. make_shared<Derived>()๋กœ ์ƒ์„ฑํ•˜๋ฉด ์ œ์–ด ๋ธ”๋ก์ด Derived์˜ ์†Œ๋ฉธ์ž๋ฅผ ๊ธฐ์–ตํ•˜๋ฏ€๋กœ, shared_ptr<Base>๋กœ ๋‹ด์•„๋„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์†Œ๋ฉธ๋ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
class Base {
public:
    ~Base() {}   // virtual ์•„๋‹ˆ์ง€๋งŒ
};
class Derived : public Base { };

std::shared_ptr<Base> p = std::make_shared<Derived>();
// ์ œ์–ด ๋ธ”๋ก์ด Derived์˜ deleter๋ฅผ ์ €์žฅ โ†’ Derived::~Derived ํ˜ธ์ถœ๋จ

ํ•˜์ง€๋งŒ ์ด๋Š” ์˜ˆ์™ธ์ด๋ฉฐ ์ผ๋ฐ˜ ๊ทœ์น™์€ โ€œ๋‹คํ˜• ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค์— virtual ์†Œ๋ฉธ์ž ํ•„์ˆ˜โ€์ž…๋‹ˆ๋‹ค. unique_ptr์€ ์ด ํŠธ๋ฆญ์ด ์—†๊ณ , shared_ptr<Base>(new Derived)์ฒ˜๋Ÿผ new๋ฅผ ์ง์ ‘ ์“ฐ๋ฉด Base์˜ deleter๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ โ†’ RAII โ†’ virtual ์†Œ๋ฉธ์ž โ†’ vtable ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.


7. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ

๋ฉ”์ธ ์งˆ๋ฌธ ๋‹ต๋ณ€ ํ›„ ์˜ˆ์ƒ ํ๋ฆ„

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"์Šค๋งˆํŠธ ํฌ์ธํ„ฐ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•ด ์ฃผ์„ธ์š”"
         โ”‚
         โ”œโ”€ 3์ข… ์„ค๋ช… (unique/shared/weak)
         โ”‚    โ””โ”€ "shared_ptr์˜ ์ฐธ์กฐ ์นด์šดํŒ…์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?"
         โ”‚         โ”œโ”€ ์ œ์–ด ๋ธ”๋ก ๊ตฌ์กฐ
         โ”‚         โ””โ”€ "์™œ atomic์ด์–ด์•ผ ํ•˜๋‚˜์š”?"
         โ”‚              โ””โ”€ "์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๋Š”?"
         โ”‚
         โ”œโ”€ ์ˆœํ™˜ ์ฐธ์กฐ / weak_ptr
         โ”‚    โ””โ”€ "weak_ptr ์—†์ด๋Š” ํ•ด๊ฒฐ ์•ˆ ๋˜๋‚˜์š”?"
         โ”‚         โ””โ”€ "lock() ์—†์ด weak_ptr ์—ญ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‚˜์š”?"
         โ”‚
         โ”œโ”€ make_shared vs new
         โ”‚    โ””โ”€ "make_shared์˜ ๋‹จ์ ๋„ ์žˆ๋‚˜์š”?" โ†’ weak_ptr ์žฅ๊ธฐ ๋ณด๊ด€ ๋ฌธ์ œ
         โ”‚
         โ””โ”€ RAII ์—ฐ๊ฒฐ
              โ””โ”€ "unique_ptr<Base>๋กœ Derived๋ฅผ ๋‹ด์„ ๋•Œ ์ฃผ์˜์ ์€?"
                   โ””โ”€ "virtual ์†Œ๋ฉธ์ž๊ฐ€ ์—†์œผ๋ฉด?" (โ˜… ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์—ฐ๊ฒฐ!)
                        โ””โ”€ "๊ทธ๋Ÿผ vtable์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋‚˜์š”?" โ† ์ด์ „ ์ฃผ์ œ ํšŒ๊ท€

๊ฐ ๊ผฌ๋ฆฌ์งˆ๋ฌธ 30์ดˆ ๋‹ต๋ณ€

Q: unique_ptr๊ณผ shared_ptr์˜ ์ฐจ์ด๋Š”?

1
2
3
4
unique_ptr  โ€” ๋‹จ๋… ์†Œ์œ , ๋ณต์‚ฌ ๋ถˆ๊ฐ€. sizeof = ํฌ์ธํ„ฐ 1๊ฐœ. ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๋กœ.
shared_ptr  โ€” ๊ณต์œ  ์†Œ์œ , ์ฐธ์กฐ ์นด์šดํŒ…. sizeof = ํฌ์ธํ„ฐ 2๊ฐœ.
              atomic ์ฆ๊ฐ ๋น„์šฉ + ์ œ์–ด ๋ธ”๋ก ํž™ ํ• ๋‹น ์˜ค๋ฒ„ํ—ค๋“œ.
๊ธฐ๋ณธ๊ฐ’์€ unique_ptr, ๊ณต์œ ๊ฐ€ ๊ผญ ํ•„์š”ํ•  ๋•Œ๋งŒ shared_ptr.

Q: ์ฐธ์กฐ ์นด์šดํŒ…์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?

1
2
3
4
5
6
7
8
shared_ptr๋Š” ์ œ์–ด ๋ธ”๋ก(ํž™)์„ ๊ณต์œ ํ•จ:
  - strong_count: shared_ptr ๊ฐœ์ˆ˜
  - weak_count: weak_ptr ๊ฐœ์ˆ˜ + (strong > 0 ? 1 : 0)

shared_ptr ๋ณต์‚ฌ โ†’ strong++ (atomic)
shared_ptr ์†Œ๋ฉธ โ†’ strong-- (atomic)
strong == 0 โ†’ ๊ด€๋ฆฌ ๊ฐ์ฒด delete
strong + weak == 0 โ†’ ์ œ์–ด ๋ธ”๋ก delete

Q: ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์™œ ๋ฐœ์ƒํ•˜๋‚˜์š”?

1
2
3
4
5
6
7
auto a = std::make_shared<Node>();    // a strong=1
auto b = std::make_shared<Node>();    // b strong=1
a->next = b;   // b strong=2
b->next = a;   // a strong=2
// ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ โ†’ a,b ๋ณ€์ˆ˜ ์†Œ๋ฉธ โ†’ ๋‘˜ ๋‹ค strong=1 (์„œ๋กœ ๊ฐ€๋ฆฌํ‚ด)
// ์˜์›ํžˆ 0 ์•ˆ ๋จ โ†’ ๋ˆ„์ˆ˜
ํ•ด๊ฒฐ: ํ•œ์ชฝ์„ weak_ptr๋กœ โ†’ strong ์ฆ๊ฐ€ ์•ˆ ํ•จ

Q: make_shared๋ฅผ ์“ฐ๋ฉด ์•ˆ ๋˜๋Š” ๊ฒฝ์šฐ๋Š”?

1
2
3
4
1) ์ปค์Šคํ…€ deleter๊ฐ€ ํ•„์š”ํ•  ๋•Œ โ€” make_shared ์ง€์› ๋ถˆ๊ฐ€
2) ํฐ ๊ฐ์ฒด + weak_ptr ์žฅ๊ธฐ ๋ณด๊ด€ โ€” ๊ฐ์ฒด ํ•ด์ œ๋˜์–ด๋„ ์ œ์–ด ๋ธ”๋ก์ด ๊ฐ์ฒด ๋ฉ”๋ชจ๋ฆฌ
   ๊นŒ์ง€ ์žก๊ณ  ์žˆ์–ด weak_ptr ์‚ด์•„์žˆ๋Š” ๋™์•ˆ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ ์ง€์—ฐ
3) new์˜ ๋ฐ˜ํ™˜๊ฐ’์„ ๋‹ค๋ฅธ API์— ๋จผ์ € ๋„˜๊ฒจ์•ผ ํ•  ๋•Œ

Q: unique_ptr์„ ํ•จ์ˆ˜์— ์–ด๋–ป๊ฒŒ ๋„˜๊ธฐ๋‚˜์š”?

1
2
3
4
์†Œ์œ ๊ถŒ ์ด์ „:    void f(std::unique_ptr<T> p);  f(std::move(up));
์†Œ์œ ๊ถŒ ์—†์ด:    void f(T* p);                   f(up.get());
                void f(T& p);                   f(*up);
๋ฐ˜ํ™˜:          std::unique_ptr<T> Create();     return std::make_unique<T>();

Q: unique_ptr์—์„œ virtual ์†Œ๋ฉธ์ž๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€์š”?

1
2
3
4
unique_ptr ์†Œ๋ฉธ์ž๋Š” Base* ํƒ€์ž…์œผ๋กœ delete ํ˜ธ์ถœ
โ†’ Base ์†Œ๋ฉธ์ž๊ฐ€ non-virtual์ด๋ฉด ์ •์  ๋ฐ”์ธ๋”ฉ โ†’ Base::~Base๋งŒ ์‹คํ–‰
โ†’ Derived::~Derived ๋ฏธํ˜ธ์ถœ โ†’ Derived ์ž์› ๋ˆ„์ˆ˜
โ†’ virtual ~Base() ๋กœ ํ•ด๊ฒฐ (vptr โ†’ vtable โ†’ ๋™์  ๋””์ŠคํŒจ์น˜)

Q: enable_shared_from_this๋Š” ์™œ ํ•„์š”ํ•œ๊ฐ€์š”?

1
2
3
4
๊ฐ์ฒด ๋‚ด๋ถ€์—์„œ this๋ฅผ ๊ทธ๋Œ€๋กœ shared_ptr๋กœ ๊ฐ์‹ธ๋ฉด ์ƒˆ ์ œ์–ด ๋ธ”๋ก์ด ์ƒ์„ฑ๋จ
โ†’ ๊ฐ™์€ ๊ฐ์ฒด์— ๋‘ ์ œ์–ด ๋ธ”๋ก โ†’ ์ด์ค‘ ํ•ด์ œ UB
enable_shared_from_this๋Š” ์ตœ์ดˆ shared_ptr ์ƒ์„ฑ ์‹œ ์ œ์–ด ๋ธ”๋ก์„ weak ์ €์žฅ
shared_from_this() ํ˜ธ์ถœ ์‹œ ๊ทธ weak_ptr๋ฅผ lockํ•ด ๊ฐ™์€ ๋ธ”๋ก ์žฌ์‚ฌ์šฉ

8. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ

๋‘ ๊ฐ€์ง€ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ์ฒด๊ณ„

์–ธ๋ฆฌ์–ผ์€ UObject ๊ณ„์—ด(GC ๊ด€๋ฆฌ)๊ณผ ์ผ๋ฐ˜ C++ ๊ฐ์ฒด(์ˆ˜๋™/์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ๊ด€๋ฆฌ)๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
8
9
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  UObject ๊ณ„์—ด              โ”‚  ์ผ๋ฐ˜ C++ ๊ฐ์ฒด               โ”‚
โ”‚  (AActor, UComponent ๋“ฑ)   โ”‚  (FVector, ์ปค์Šคํ…€ struct)    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Unreal GC (Mark & Sweep)  โ”‚  TSharedPtr / TUniquePtr     โ”‚
โ”‚  UPROPERTY()๋กœ ๋“ฑ๋ก        โ”‚  std::shared_ptr ๊ณ„์—ด        โ”‚
โ”‚  TWeakObjectPtr<T>         โ”‚  TWeakPtr<T>                 โ”‚
โ”‚  IsValid() ์ฒดํฌ            โ”‚  lock() ์ฒดํฌ                 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

TSharedPtr / TUniquePtr / TWeakPtr โ€” std ๋Œ€์‘

1
2
3
4
5
6
7
8
9
10
// std ๋ฒ„์ „
std::unique_ptr<MyData> p1 = std::make_unique<MyData>();
std::shared_ptr<MyData> p2 = std::make_shared<MyData>();
std::weak_ptr<MyData> w = p2;

// ์–ธ๋ฆฌ์–ผ ๋ฒ„์ „ (์ผ๋ฐ˜ C++ ๊ฐ์ฒด์šฉ, UObject์—๋Š” ์‚ฌ์šฉ ๊ธˆ์ง€)
TUniquePtr<FMyData> p1 = MakeUnique<FMyData>();
TSharedPtr<FMyData> p2 = MakeShared<FMyData>();
TSharedRef<FMyData> r = p2.ToSharedRef();   // nullptr ๋ถˆ๊ฐ€ ๋ฒ„์ „
TWeakPtr<FMyData> w = p2;

TSharedRef โ€” null ๋ถˆ๊ฐ€ ๊ณต์œ  ํฌ์ธํ„ฐ

1
2
3
4
5
6
7
// TSharedPtr์€ nullptr ๊ฐ€๋Šฅ โ€” std::shared_ptr์™€ ์œ ์‚ฌ
TSharedPtr<FMyData> p = MakeShared<FMyData>();
if (p.IsValid()) { p->Foo(); }

// TSharedRef๋Š” nullptr ๋ถˆ๊ฐ€ โ€” ํ•ญ์ƒ ์œ ํšจํ•จ์„ ํƒ€์ž…์œผ๋กœ ๋ณด์žฅ
TSharedRef<FMyData> r = MakeShared<FMyData>();
r->Foo();   // IsValid ์ฒดํฌ ๋ถˆํ•„์š”

UObject์—์„œ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ์‚ฌ์šฉ ๊ธˆ์ง€

1
2
3
4
5
6
7
8
9
10
11
// โŒ ์ ˆ๋Œ€ ๊ธˆ์ง€ โ€” GC์™€ ์ถฉ๋Œ, ํฌ๋ž˜์‹œ ์œ ๋ฐœ
TSharedPtr<AActor> Actor = MakeShared<AActor>();   // NO!
std::unique_ptr<UWidget> W;                        // NO!

// โœ… UObject๋Š” GC์— ๋งก๊ธด๋‹ค
UPROPERTY()
AActor* Actor;                     // UPROPERTY๋กœ GC๊ฐ€ ์ถ”์ 

// ์†Œ์œ ๊ถŒ ์—†์ด ๊ด€์ฐฐ๋งŒ
TWeakObjectPtr<AActor> WeakActor;  // weak_ptr์˜ UObject ๋ฒ„์ „
if (WeakActor.IsValid()) { WeakActor->Foo(); }

๋น„๊ต ํ‘œ

ย std์–ธ๋ฆฌ์–ผ (์ผ๋ฐ˜ C++)์–ธ๋ฆฌ์–ผ (UObject)
๋‹จ๋… ์†Œ์œ unique_ptrTUniquePtrUPROPERTY() + GC
๊ณต์œ  ์†Œ์œ shared_ptrTSharedPtr / TSharedRefUPROPERTY() + GC
์•ฝํ•œ ์ฐธ์กฐweak_ptrTWeakPtrTWeakObjectPtr
ํŒฉํ† ๋ฆฌmake_*MakeUnique, MakeSharedNewObject<T>()
ํ•ด์ œ ์กฐ๊ฑด์นด์šดํŠธ 0์นด์šดํŠธ 0GC๊ฐ€ ๋„๋‹ฌ ๋ถˆ๊ฐ€ ํŒ์ •
์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€๋Šฅ (์ง์ ‘ ํ•ด๊ฒฐ)๊ฐ€๋Šฅ (์ง์ ‘ ํ•ด๊ฒฐ)๋ถˆ๊ฐ€๋Šฅ (GC๊ฐ€ ์ฒ˜๋ฆฌ)

์–ธ๋ฆฌ์–ผ GC๊ฐ€ ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ์ž๋™ ํ•ด๊ฒฐํ•˜๋Š” ์ด์œ 

  • Unreal GC๋Š” Mark & Sweep ๋ฐฉ์‹
  • ๋ฃจํŠธ ์˜ค๋ธŒ์ ํŠธ(GameInstance, World ๋“ฑ)์—์„œ ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ UObject๋งŒ ์‚ด๋ ค๋‘ 
  • ์„œ๋กœ ์ฐธ์กฐํ•˜๋Š” UObject๋ผ๋„ ๋ฃจํŠธ์—์„œ ๋„๋‹ฌ ๋ถˆ๊ฐ€๋ฉด ๋ชจ๋‘ ์ˆ˜๊ฑฐ
  • ๋”ฐ๋ผ์„œ UObject๋ผ๋ฆฌ UPROPERTY()๋กœ ์„œ๋กœ ์ฐธ์กฐํ•ด๋„ weak_ptr ๊ณ ๋ฏผ ๋ถˆํ•„์š”
  • ์ผ๋ฐ˜ C++ ๊ฐ์ฒด(TSharedPtr)๋Š” ์ฐธ์กฐ ์นด์šดํŒ…์ด๋ผ ์—ฌ์ „ํžˆ ์ˆœํ™˜ ์ฃผ์˜

์ฐธ๊ณ 

  • 09_rtti_raii.md โ€” RAII์™€ ์˜ˆ์™ธ ์•ˆ์ „์„ฑ, virtual ์†Œ๋ฉธ์ž ์—ฐ๊ฒฐ
  • 06_virtual_destructor.md โ€” virtual ์†Œ๋ฉธ์ž ์ƒ์„ธ
  • 08_vtable_deepdive.md โ€” vtable ๊ตฌ์กฐ ์‹ฌํ™”
  • 10_pointer_deepdive.md โ€” ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ์™€ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ๋ฐฉ์–ด ์ „๋žต
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

ยฉ GoldBoll. ์ผ๋ถ€ ๊ถŒ๋ฆฌ ๋ณด์œ 

Powered by Jekyll with Chirpy theme

์ธ๊ธฐ ํƒœ๊ทธ