๐ 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>์์ ํ์ ๊ฐ์ฒด ์๋ฉธ ์ ํ์ ์กฐ๊ฑด
๋ชฉ์ฐจ
- ํต์ฌ ์์ฝ ์นด๋
- unique_ptr โ ๋จ๋
์์
- shared_ptr โ ๊ณต์ ์์ + ์ฐธ์กฐ ์นด์ดํ
- weak_ptr โ ์ํ ์ฐธ์กฐ ํด๊ฒฐ
- make_unique vs make_shared vs new
- RAII ๋ฐ virtual ์๋ฉธ์์์ ์ฐ๊ฒฐ
- ๊ผฌ๋ฆฌ์ง๋ฌธ ์์ ๊ฒฝ๋ก
- ์ธ๋ฆฌ์ผ์์์ ์ค๋งํธ ํฌ์ธํฐ
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ํ (๊ฐ์ฒด+์ ์ด๋ธ๋ก) |
| ์ปค์คํ
deleter | N/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_ptr | TUniquePtr | UPROPERTY() + GC |
| ๊ณต์ ์์ | shared_ptr | TSharedPtr / TSharedRef | UPROPERTY() + GC |
| ์ฝํ ์ฐธ์กฐ | weak_ptr | TWeakPtr | TWeakObjectPtr |
| ํฉํ ๋ฆฌ | make_* | MakeUnique, MakeShared | NewObject<T>() |
| ํด์ ์กฐ๊ฑด | ์นด์ดํธ 0 | ์นด์ดํธ 0 | GC๊ฐ ๋๋ฌ ๋ถ๊ฐ ํ์ |
| ์ํ ์ฐธ์กฐ | ๊ฐ๋ฅ (์ง์ ํด๊ฒฐ) | ๊ฐ๋ฅ (์ง์ ํด๊ฒฐ) | ๋ถ๊ฐ๋ฅ (GC๊ฐ ์ฒ๋ฆฌ) |
์ธ๋ฆฌ์ผ GC๊ฐ ์ํ ์ฐธ์กฐ๋ฅผ ์๋ ํด๊ฒฐํ๋ ์ด์
- Unreal GC๋ Mark & Sweep ๋ฐฉ์
- ๋ฃจํธ ์ค๋ธ์ ํธ(GameInstance, World ๋ฑ)์์ ๋๋ฌ ๊ฐ๋ฅํ UObject๋ง ์ด๋ ค๋
- ์๋ก ์ฐธ์กฐํ๋ UObject๋ผ๋ ๋ฃจํธ์์ ๋๋ฌ ๋ถ๊ฐ๋ฉด ๋ชจ๋ ์๊ฑฐ
- ๋ฐ๋ผ์ UObject๋ผ๋ฆฌ
UPROPERTY()๋ก ์๋ก ์ฐธ์กฐํด๋ weak_ptr ๊ณ ๋ฏผ ๋ถํ์ - ์ผ๋ฐ C++ ๊ฐ์ฒด(
TSharedPtr)๋ ์ฐธ์กฐ ์นด์ดํ
์ด๋ผ ์ฌ์ ํ ์ํ ์ฃผ์
์ฐธ๊ณ