๐ 04/24 โ RTTI & RAII ๋ชจ์๋ฉด์ ์ค๋น
๋ด์ผ ๋ชจ์๋ฉด์ ์ฃผ์ : โRTTI์ RAII์ ๋ํด์ ์ค๋ช
ํด ์ฃผ์ธ์โ RAII โ ์ค๋งํธ ํฌ์ธํฐ โ virtual ์๋ฉธ์ โ vtable ๊ผฌ๋ฆฌ์ง๋ฌธ ์ฐ๊ฒฐ ๋ค๋ฆฌ
๋ชจ์๋ฉด์ ๋ต๋ณ
RTTI(Runtime Type Information)๋ C++์ด ๋ฐํ์์ ๊ฐ์ฒด์ ์ค์ ํ์
์ ๋ณด๋ฅผ ์ป์ ์ ์๊ฒ ํ๋ ๋ฉ์ปค๋์ฆ์
๋๋ค. virtual ํจ์๊ฐ ํ๋๋ผ๋ ์๋ ํด๋์ค๋ vtable์ ๊ฐ์ง๋ฉฐ, vtable ํค๋์ type_info ํฌ์ธํฐ๊ฐ ์๋ ์ฝ์
๋ฉ๋๋ค. typeid(*ptr)๋ vptr์ ํตํด ์ด type_info์ ์ ๊ทผํด ์ค์ ํ์
์ด๋ฆ์ ๋ฐํํ๊ณ , dynamic_cast๋ RTTI๋ฅผ ์ด์ฉํด ๋ค์ด์บ์คํธ๋ฅผ ์๋ํ ๋ค ์คํจํ๋ฉด nullptr(ํฌ์ธํฐ) ๋๋ std::bad_cast ์์ธ(์ฐธ์กฐ)๋ฅผ ๋ฐํํด ์์ ํ๊ฒ ์ฒ๋ฆฌํฉ๋๋ค. static_cast๋ ๋ฐํ์ ๊ฒ์ฌ ์์ด ๊ฐ์ ๋ณํํ๋ฏ๋ก ํ์
์ด ํ๋ฆฌ๋ฉด ๋ฏธ์ ์ ๋์(UB)์ด ๋ฐ์ํฉ๋๋ค.
RAII(Resource Acquisition Is Initialization)๋ ์์์ ์๋ช
์ ๊ฐ์ฒด์ ์๋ช
์ ๋ฌถ๋ C++ ๊ด์ฉ๊ตฌ์
๋๋ค. ์์ฑ์์์ ์์์ ํ๋ํ๊ณ ์๋ฉธ์์์ ํด์ ํ๋ฉด, ์์ธ ๋ฐ์ ์ ์คํ ํด์ (stack unwinding) ๊ณผ์ ์์ ์๋ฉธ์๊ฐ ์๋ ํธ์ถ๋์ด ๋์ ์์ด ์ ๋ฆฌ๋ฉ๋๋ค. unique_ptr, shared_ptr, lock_guard, weak_ptr, ifstream์ด ๋ชจ๋ RAII ๋๊ตฌ์
๋๋ค. ๋จ, ๊ธฐ๋ฐ ํด๋์ค ํฌ์ธํฐ๋ก ํ์ ๊ฐ์ฒด๋ฅผ deleteํ ๋ virtual ์๋ฉธ์๊ฐ ์์ผ๋ฉด ํ์ ์๋ฉธ์๊ฐ ํธ์ถ๋์ง ์์ ์์ ๋์๊ฐ ๋ฐ์ํ๋ฏ๋ก, ๋คํ์ ๊ธฐ๋ฐ ํด๋์ค์๋ ๋ฐ๋์ virtual ~Base()๋ฅผ ์ ์ธํด์ผ ํฉ๋๋ค.
ํต์ฌ ๊ฐ๋
- RTTI (Runtime Type Information) โ ๋ฐํ์์ ๊ฐ์ฒด์ ์ค์ ํ์
์ ํ์ธํ๋ ๋ฉ์ปค๋์ฆ.
virtual ํจ์๊ฐ ์๋ ํด๋์ค์ vtable ํค๋์ type_info* ํฌ์ธํฐ๊ฐ ์๋ ์์ฑ๋จ - typeid โ ํ์
์ ๋ณด๋ฅผ ๋ฐํํ๋ ์ฐ์ฐ์.
typeid(*ptr)์ vptr ๊ฒฝ์ ๋์ ํ์
(๋ฐํ์), typeid(ptr)์ ์ ์ ํ์
(์ปดํ์ผ ํ์) ๋ฐํ - dynamic_cast โ RTTI๋ฅผ ์ฌ์ฉํด ๋ฐํ์ ์์ ๋ค์ด์บ์คํธ. ์คํจ ์ ํฌ์ธํฐ โ
nullptr, ์ฐธ์กฐ โ std::bad_cast ์์ธ - static_cast โ ์ปดํ์ผ ํ์ ํ์
๋ณํ. ๋ฐํ์ ๊ฒ์ฌ ์์ โ ์๋ชป๋ ์บ์คํธ ์ Undefined Behavior
- type_info โ RTTI ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ๊ตฌ์กฐ์ฒด. vtable[-1] ์์น์ ํฌ์ธํฐ๋ก ์ ์ฅ.
name() ๋ฉ์๋๋ก ํ์
์ด๋ฆ ๋ฐํ - -fno-rtti โ GCC/Clang์์ RTTI๋ฅผ ๋นํ์ฑํํ๋ ์ปดํ์ผ ํ๋๊ทธ.
dynamic_cast/typeid ์ฌ์ฉ ๋ถ๊ฐ. ์ฑ๋ฅ ์ค์ฌ ํ๊ฒฝ(๊ฒ์ ์์ง ๋ฑ)์์ ํ์ฉ - RAII (Resource Acquisition Is Initialization) โ ์์ ์๋ช
์ ๊ฐ์ฒด ์๋ช
์ ๋ฌถ๋ C++ ๊ด์ฉ๊ตฌ. ์์ฑ์์์ ํ๋, ์๋ฉธ์์์ ํด์
- ์คํ ํด์ (Stack Unwinding) โ ์์ธ ๋ฐ์ ๋๋ ํจ์ ์ข
๋ฃ ์ ์คํ ํ๋ ์์ด ์ญ์์ผ๋ก ์๋ฉธ๋๋ฉด์ ์๋ฉธ์๊ฐ ์๋ ํธ์ถ๋๋ ๊ณผ์
- ์์ธ ์์ ์ฑ (Exception Safety) โ ์์ธ ๋ฐ์ ๊ฒฝ๋ก์์๋ ์์์ด ๋์ ์์ด ํด์ ๋๋ ์์ฑ. RAII๋ก ๋ณด์ฅ
- unique_ptr โ ๋จ๋
์์ ๊ถ ์ค๋งํธ ํฌ์ธํฐ. ๋ณต์ฌ ๋ถ๊ฐ, move๋ง ํ์ฉ. ๋ฐํ์ ์ค๋ฒํค๋ ์์
- shared_ptr โ ์ฐธ์กฐ ์นด์ดํ
๊ณต์ ์์ ๊ถ ์ค๋งํธ ํฌ์ธํฐ. ์นด์ดํธ๊ฐ 0์ด ๋๋ฉด ์๋
delete - weak_ptr โ ์์ ๊ถ ์๋ ์ฝํ ์ฐธ์กฐ.
shared_ptr ์ํ ์ฐธ์กฐ ๋ฌธ์ ํด๊ฒฐ์ ์ฌ์ฉ - lock_guard โ ๋ฎคํ
์ค๋ฅผ RAII๋ก ๊ฐ์ผ ๋ํผ. ์์ฑ์์์
lock(), ์๋ฉธ์์์ unlock(). ์์ธ ๋ฐ์ ์ ๋ฐ๋๋ฝ ๋ฐฉ์ง - ifstream โ ํ์ผ ํธ๋ค์ RAII๋ก ๊ด๋ฆฌํ๋ ํ์ผ ์คํธ๋ฆผ. ์์ฑ์์์ ํ์ผ ์ด๊ธฐ, ์๋ฉธ์์์ ์๋
fclose. ์์ธ ๋ฐ์ ์ ํ์ผ ํธ๋ค ๋์ ๋ฐฉ์ง - virtual ์๋ฉธ์ โ RAII + ๋คํ์ฑ ์กฐํฉ์ ํ์ ์กฐ๊ฑด. ๊ธฐ๋ฐ ํฌ์ธํฐ
delete ์ ํ์ ์๋ฉธ์๊น์ง ์ฌ๋ฐ๋ฅด๊ฒ ์ฒด์ธ ํธ์ถ๋จ
๋ชฉ์ฐจ
- ํต์ฌ ์์ฝ ์นด๋
- RTTI โ Runtime Type Information
- RAII โ Resource Acquisition Is Initialization
- ๊ผฌ๋ฆฌ์ง๋ฌธ ์์ ๊ฒฝ๋ก
- ์ธ๋ฆฌ์ผ์์์ RTTI / RAII
1. ํต์ฌ ์์ฝ ์นด๋
RTTI 30์ด
1
2
3
4
5
| RTTI = ๋ฐํ์ ํ์
์ ๋ณด ์์คํ
๋ฉ์ปค๋์ฆ: vtable ํค๋์ type_info* ํฌ์ธํฐ
๋๊ตฌ: typeid (ํ์
์ด๋ฆ), dynamic_cast (์์ ์บ์คํ
)
๋น์ฉ: vtable ํ์ ์ค๋ฒํค๋ โ ์ฑ๋ฅ ์ค์ฌ ํ๊ฒฝ์์ -fno-rtti
์ธ๋ฆฌ์ผ: Cast<T>(), IsA<T>(), GetClass() (UClass ๊ธฐ๋ฐ)
|
RAII 30์ด
1
2
3
4
5
| RAII = ์์ ์๋ช
= ๊ฐ์ฒด ์๋ช
์์ฑ์์์ ํ๋, ์๋ฉธ์์์ ํด์ โ ์์ธ ์์ ์ฑ ๋ณด์ฅ
๋๊ตฌ: unique_ptr, shared_ptr, lock_guard, ifstream
์ธ๋ฆฌ์ผ: FScopeLock, TGuardValue, FString/TArray
ํจ์ : ๊ธฐ๋ฐ ํด๋์ค ํฌ์ธํฐ๋ก delete ์ virtual ์๋ฉธ์ ํ์
|
๊ผฌ๋ฆฌ์ง๋ฌธ ์ฐ๊ฒฐ ๋งต
1
2
3
4
5
6
7
8
9
10
11
12
13
| RTTI
โโโ typeid โ ์ ์ /๋์ RTTI ๊ตฌ๋ถ
โโโ dynamic_cast โ ์คํจ ์ nullptr vs bad_cast
โ โโโ static_cast ๋น๊ต โ UB ์ํ
โโโ -fno-rtti โ ์ฑ๋ฅ ํธ๋ ์ด๋์คํ
RAII
โโโ unique_ptr โ ๋จ๋
์์ , move semantics
โโโ shared_ptr โ ์ฐธ์กฐ ์นด์ดํ
, ์ํ ์ฐธ์กฐ ๋ฌธ์
โ โโโ weak_ptr โ ์ํ ์ฐธ์กฐ ํด๊ฒฐ
โโโ lock_guard โ ๋ฎคํ
์ค + RAII
โโโ virtual ์๋ฉธ์ (โ
๊ผฌ๋ฆฌ์ง๋ฌธ ์ฐ๊ฒฐ!)
โโโ vtable โ ๋์ ๋์คํจ์น (์ ๋ ์ฃผ์ ๋ณต์ต)
|
ํต์ฌ ํ ๋ฌธ์ฅ
RTTI๋ C++์ด ๋ฐํ์์ ๊ฐ์ฒด์ ์ค์ ํ์
์ ๋ณด๋ฅผ ์ป์ ์ ์๊ฒ ํ๋ ๋ฉ์ปค๋์ฆ์ผ๋ก, typeid์ dynamic_cast์ ๊ธฐ๋ฐ ์ธํ๋ผ์
๋๋ค.
๋์ ์๋ฆฌ
virtual ํจ์๊ฐ ์๋ ํด๋์ค๋ vtable์ ๊ฐ์ง๋ฉฐ, vtable ํค๋์ type_info ํฌ์ธํฐ๊ฐ ์๋ ์ฝ์
๋ฉ๋๋ค.
1
2
3
4
5
| vtable ๊ตฌ์กฐ:
[ type_info* ] โ RTTI ๋ฐ์ดํฐ (vtable[-1])
[ offset_to_top ] โ ๋ค์ค ์์์ฉ ํฌ์ธํฐ ์กฐ์ ๊ฐ (vtable[-2])
[ Func1* ] โ ๊ฐ์ ํจ์ [0]
[ Func2* ] โ ๊ฐ์ ํจ์ [1]
|
typeid โ ํ์
์ด๋ฆ ํ์ธ
1
2
3
4
5
6
7
8
9
10
11
12
| #include <typeinfo>
class Animal { public: virtual ~Animal() {} };
class Dog : public Animal {};
Animal* a = new Dog();
// ์ ์ RTTI (์ปดํ์ผ ํ์) โ ํฌ์ธํฐ ํ์
๊ธฐ์ค
std::cout << typeid(a).name(); // "Animal*"
// ๋์ RTTI (๋ฐํ์) โ vptr โ type_info ์ ๊ทผ
std::cout << typeid(*a).name(); // "Dog" โ ์ค์ ํ์
!
|
dynamic_cast โ ์์ ํ ๋ค์ด์บ์คํธ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| Animal* a = new Dog();
// ์ฑ๊ณต ์ผ์ด์ค
Dog* d = dynamic_cast<Dog*>(a); // Dog ๋ง์ โ ์ ํจ ํฌ์ธํฐ ๋ฐํ
if (d) { d->Bark(); }
// ์คํจ ์ผ์ด์ค
Cat* c = dynamic_cast<Cat*>(a); // Dog์ด์ง Cat์ด ์๋ โ nullptr ๋ฐํ
if (!c) { /* ์์ ํ๊ฒ ์ฒ๋ฆฌ */ }
// ๋ ํผ๋ฐ์ค ๋ฒ์ โ ์คํจ ์ std::bad_cast ์์ธ ๋์ง
try {
Cat& cr = dynamic_cast<Cat&>(*a);
} catch (const std::bad_cast& e) { }
|
dynamic_cast vs static_cast
| ย | static_cast | dynamic_cast |
|---|
| ๊ฒ์ฌ ์์ | ์ปดํ์ผ ํ์ | ๋ฐํ์ (RTTI ์ฌ์ฉ) |
| ์คํจ ์ | UB (ํฌ๋์ ๊ฐ๋ฅ) | nullptr / bad_cast |
| ์๋ | ๋น ๋ฆ | ๋๋ฆผ (vtable ํ์) |
| ์กฐ๊ฑด | ํ์
ํ์ ํ ๋ | ํ์
๋ถํ์คํ ๋ ์์ ํ๊ฒ |
| RTTI ํ์ | ๋ถํ์ | ํ์ |
1
2
3
4
5
6
| // static_cast ์๋ชป๋ ์ฌ์ฉ โ UB
Animal* a = new Animal();
Dog* d = static_cast<Dog*>(a); // ์ปดํ์ผ์ ๋จ, ๋ฐํ์ UB!
// dynamic_cast ์์ ํ ์ฌ์ฉ
Dog* d = dynamic_cast<Dog*>(a); // nullptr ๋ฐํ โ ์์
|
RTTI ๋น์ฉ๊ณผ ๋นํ์ฑํ
- ๋น์ฉ: type_info ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ ์ฆ๊ฐ + vtable ํ์ ์ค๋ฒํค๋
- ๋นํ์ฑํ:
-fno-rtti (GCC/Clang) โ ๊ฒ์ ์์ง ๋ฑ ์ฑ๋ฅ ์ค์ฌ ํ๊ฒฝ - ๋นํ์ฑํ ์ ๋ถ๊ฐ:
dynamic_cast, typeid (์ปดํ์ผ ์ค๋ฅ)
3. RAII โ Resource Acquisition Is Initialization
ํต์ฌ ํ ๋ฌธ์ฅ
RAII๋ ์์์ ์๋ช
์ ๊ฐ์ฒด์ ์๋ช
์ ๋ฌถ๋ C++ ๊ด์ฉ๊ตฌ์
๋๋ค. ์์ฑ์์์ ์์์ ํ๋ํ๊ณ , ์๋ฉธ์์์ ์์์ ํด์ ํ์ฌ ์์ธ๊ฐ ๋ฐ์ํด๋ ๋์ ์์ด ์ ๋ฆฌํฉ๋๋ค.
๋ฌธ์ : ์์ธ ๋ฐ์ ์ ์์ ๋์
1
2
3
4
5
6
| // RAII ๋ฏธ์ ์ฉ โ ์ํํ ์ฝ๋
void BadFunction() {
int* data = new int[1000];
DoSomething(); // ์์ธ ๋ฐ์ ์ โ
delete[] data; // ์ด ์ค ์คํ ์ ๋จ! โ ๋ฉ๋ชจ๋ฆฌ ๋์
}
|
ํด๊ฒฐ: RAII ํจํด
1
2
3
4
5
6
| // RAII ์ ์ฉ โ ์คํ ๊ฐ์ฒด ์๋ฉธ์๊ฐ ์์ ํด์ ๋ณด์ฅ
void GoodFunction() {
std::unique_ptr<int[]> data = std::make_unique<int[]>(1000);
DoSomething(); // ์์ธ ๋ฐ์ํด๋ OK
// ํจ์ ์ข
๋ฃ ๋๋ ์์ธ ๋ฐ์ โ data ์๋ฉธ์ ์๋ ํธ์ถ โ delete[] ์คํ
}
|
RAII ๋์ ์๋ฆฌ
1
2
3
4
5
| ์คํ ํ๋ ์ ์ข
๋ฃ (์ ์ / ์์ธ / return) ์ ์คํ ๊ฐ์ฒด ์๋ฉธ์ ์๋ ํธ์ถ
โ
์๋ฉธ์ ์์์ ์์ ํด์ (delete, fclose, unlock, ...)
โ
์์ ๋์ ์์ โ ์์ธ ์์ (Exception Safety) ๋ณด์ฅ
|
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ RAII ๋๊ตฌ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // 1. ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ
std::unique_ptr<T> p = std::make_unique<T>(); // ๋จ๋
์์ , ๋ณต์ฌ ๋ถ๊ฐ
std::shared_ptr<T> p = std::make_shared<T>(); // ์ฐธ์กฐ ์นด์ดํ
๊ณต์ ์์
std::weak_ptr<T> w = shared; // ์์ ๊ถ ์๋ ์ฝํ ์ฐธ์กฐ
// 2. ๋ฎคํ
์ค ์ ๊ธ
std::mutex m;
{
std::lock_guard<std::mutex> lock(m); // ์์ฑ์: lock(), ์๋ฉธ์: unlock()
// ์๊ณ ๊ตฌ์ญ
} // ์๋ unlock โ ์์ธ ๋ฐ์ํด๋ unlock ๋ณด์ฅ
// 3. ํ์ผ ํธ๋ค
std::ifstream file("data.txt"); // ์์ฑ์: fopen, ์๋ฉธ์: fclose
// file์ด ์ค์ฝํ ์ข
๋ฃ ์ ์๋์ผ๋ก ๋ซํ
|
lock_guard โ ๋ฎคํ
์ค RAII ๋ํผ
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๊ณต์ ์์์ ์ ๊ทผํ ๋ mutex๋ก ์ ๊ธ์ ๊ฒ๋๋ค. ๊ทธ๋ฐ๋ฐ ์ ๊ธ ํ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด unlock()์ด ํธ์ถ๋์ง ์์ ๋ฐ๋๋ฝ์ด ๋ฐ์ํ ์ ์์ต๋๋ค. lock_guard๋ ์ด๊ฑธ RAII๋ก ํด๊ฒฐํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| std::mutex m;
int shared_data = 0;
void Increment() {
// RAII ๋ฏธ์ ์ฉ โ ์ํ
m.lock();
shared_data++;
if (shared_data < 0) throw std::runtime_error("์์!"); // ์์ธ ๋ฐ์
m.unlock(); // ์์ธ ๋ฐ์ ์ ์ด ์ค ์คํ ์ ๋จ โ ๋ฐ๋๋ฝ!
}
void SafeIncrement() {
std::lock_guard<std::mutex> lock(m); // ์์ฑ์: m.lock()
shared_data++;
if (shared_data < 0) throw std::runtime_error("์์!");
// ์์ธ ๋ฐ์ํด๋ lock ์๋ฉธ์์์ m.unlock() ์๋ ํธ์ถ โ ๋ฐ๋๋ฝ ์์
}
|
- ์์ฑ์:
mutex.lock() ํธ์ถ - ์๋ฉธ์:
mutex.unlock() ํธ์ถ - ์ค์ฝํ๋ฅผ ๋ฒ์ด๋๋ฉด (์ ์ ์ข
๋ฃ / ์์ธ / return) ํญ์ unlock ๋ณด์ฅ
ifstream โ ํ์ผ ํธ๋ค RAII ๋ํผ
ํ์ผ์ fopen์ผ๋ก ์ด๋ฉด ๋ฐ๋์ fclose๋ก ๋ซ์์ผ ํฉ๋๋ค. ์์ธ ๋ฐ์ ์ ๋ซ์ง ๋ชปํ๋ฉด ํ์ผ ๋์คํฌ๋ฆฝํฐ๊ฐ ๋์๋ฉ๋๋ค. ifstream์ ์ด๊ฑธ RAII๋ก ์ฒ๋ฆฌํฉ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // C ์คํ์ผ โ ์ํ
FILE* f = fopen("data.txt", "r");
ProcessData(f); // ์์ธ ๋ฐ์ ์
fclose(f); // ์ด ์ค ์คํ ์ ๋จ โ ํ์ผ ํธ๋ค ๋์
// ifstream RAII โ ์์
{
std::ifstream file("data.txt"); // ์์ฑ์: ํ์ผ ์ด๊ธฐ
if (!file.is_open()) { /* ์๋ฌ ์ฒ๋ฆฌ */ }
std::string line;
while (std::getline(file, line)) {
ProcessLine(line); // ์์ธ ๋ฐ์ํด๋ OK
}
} // ์๋ฉธ์: ํ์ผ ์๋ ๋ซํ โ fclose ์ง์ ํธ์ถ ๋ถํ์
|
- ์์ฑ์: ํ์ผ ์ด๊ธฐ
- ์๋ฉธ์: ํ์ผ ์๋ ๋ซ๊ธฐ
ofstream(์ฐ๊ธฐ), fstream(์ฝ๊ธฐ+์ฐ๊ธฐ)๋ ๋์ผํ RAII ํจํด
RAII ์ง์ ๊ตฌํ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| template<typename T>
class ScopedArray {
T* ptr;
public:
explicit ScopedArray(size_t n) : ptr(new T[n]) { }
~ScopedArray() { delete[] ptr; } // ์๋ฉธ์์์ ์์ ํด์
// ๋ณต์ฌ ๊ธ์ง (์ด์ค ํด์ ๋ฐฉ์ง)
ScopedArray(const ScopedArray&) = delete;
ScopedArray& operator=(const ScopedArray&) = delete;
T& operator[](size_t i) { return ptr[i]; }
};
void SafeFunction() {
ScopedArray<int> data(1000);
// ์์ธ, return ๋ฌด๊ด โ data ์๋ฉธ์๊ฐ delete[] ๋ณด์ฅ
}
|
RAII์ virtual ์๋ฉธ์์ ๊ด๊ณ (๊ผฌ๋ฆฌ์ง๋ฌธ ์ฐ๊ฒฐ!)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // unique_ptr + ๊ธฐ๋ฐ ํด๋์ค ํฌ์ธํฐ ์ฌ์ฉ ์
class Base {
public:
~Base() { } // virtual ์๋!
};
class Derived : public Base {
int* data;
public:
Derived() { data = new int[100]; }
~Derived() { delete[] data; }
};
std::unique_ptr<Base> p = std::make_unique<Derived>();
// p ์๋ฉธ โ Base::~Base() ๋ง ํธ์ถ โ Derived::~Derived() ๋ฏธํธ์ถ โ ๋์!
// ํด๊ฒฐ:
class Base {
public:
virtual ~Base() { } // virtual ์๋ฉธ์ ํ์!
};
// ์ด์ : p ์๋ฉธ โ Derived::~Derived() โ Base::~Base() ์์ ์ ์ ํธ์ถ
|
์ด๊ฒ์ด RAII โ ์ค๋งํธ ํฌ์ธํฐ โ virtual ์๋ฉธ์ โ vtable ๊ผฌ๋ฆฌ์ง๋ฌธ ์ฐ๊ฒฐ ๊ฒฝ๋ก์
๋๋ค.
4. ๊ผฌ๋ฆฌ์ง๋ฌธ ์์ ๊ฒฝ๋ก
๋ฉ์ธ ์ง๋ฌธ ๋ต๋ณ ํ ์์ ํ๋ฆ
1
2
3
4
5
6
7
8
9
10
11
12
| "RTTI์ RAII์ ๋ํด์ ์ค๋ช
ํด ์ฃผ์ธ์"
โ
โโ RTTI ์ค๋ช
โ โโ "dynamic_cast์ static_cast ์ฐจ์ด๋?"
โ โโ "RTTI ๋น์ฉ์?" โ "-fno-rtti ์ต์
"
โ
โโ RAII ์ค๋ช
โโ "์ค๋งํธ ํฌ์ธํฐ ์ข
๋ฅ์ ์ฐจ์ด๋?"
โโ unique_ptr vs shared_ptr vs weak_ptr
โโ "์ unique_ptr<Base>์์ virtual ์๋ฉธ์๊ฐ ํ์ํ๊ฐ์?"
โโ "virtual ์๋ฉธ์๊ฐ ์์ผ๋ฉด ์ด๋ป๊ฒ ๋๋์?"
โโ "๊ทธ๋ผ vtable์ด ์ด๋ค ์ญํ ์ ํ๋์?" โ ์ ๋ ์ฃผ์ ๋ก ํ๊ท!
|
๊ฐ ๊ผฌ๋ฆฌ์ง๋ฌธ 30์ด ๋ต๋ณ
Q: ์ค๋งํธ ํฌ์ธํฐ 3์ข
์ฐจ์ด?
1
2
3
| unique_ptr โ ๋จ๋
์์ , ๋ณต์ฌ ๋ถ๊ฐ, move๋ง ๊ฐ๋ฅ. ์ค๋ฒํค๋ ์ ๋ก.
shared_ptr โ ์ฐธ์กฐ ์นด์ดํ
๊ณต์ ์์ . ์นด์ดํธ๊ฐ 0์ด ๋๋ฉด delete.
weak_ptr โ ์์ ๊ถ ์๋ ๊ด์ฐฐ์. ์ํ ์ฐธ์กฐ ๋ฐฉ์ง์ ์ฌ์ฉ.
|
Q: shared_ptr ์ํ ์ฐธ์กฐ๋?
1
2
3
4
5
6
7
| struct Node {
std::shared_ptr<Node> next; // ์ํ ์ฐธ์กฐ โ ์นด์ดํธ ์ ๋ 0 ์ ๋จ โ ๋์
};
// ํด๊ฒฐ: ํ์ชฝ์ weak_ptr๋ก ๊ต์ฒด
struct Node {
std::weak_ptr<Node> next; // ์์ ๊ถ ์์ โ ์ํ ์๋
};
|
Q: RAII์ ์์ธ ์์ ์ฑ์ ๊ด๊ณ?
์คํ ํด์ (stack unwinding) ์ ์๋ฉธ์๊ฐ ๋ฐ๋์ ํธ์ถ๋๋ฏ๋ก, ์์์ ์คํ ๊ฐ์ฒด(RAII ๋ํผ)๋ก ๊ด๋ฆฌํ๋ฉด ์์ธ ๋ฐ์ ๊ฒฝ๋ก์์๋ ์์ ํด์ ๊ฐ ๋ณด์ฅ๋ฉ๋๋ค.
5. ์ธ๋ฆฌ์ผ์์์ RTTI / RAII
์ธ๋ฆฌ์ผ RTTI โ Cast vs dynamic_cast
์ธ๋ฆฌ์ผ์ ์์ฒด ๋ฆฌํ๋ ์
์์คํ
(UClass)์ ์ฌ์ฉํ๋ฏ๋ก dynamic_cast ๋์ Cast<T>๋ฅผ ์๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
| AActor* Actor = GetOwner();
// ์ธ๋ฆฌ์ผ ๋ฐฉ์ (UObject ๋ฆฌํ๋ ์
์ฌ์ฉ)
AMyCharacter* Char = Cast<AMyCharacter>(Actor);
if (Char) { /* ์ฑ๊ณต */ }
// IsA โ ํ์
์ฒดํฌ๋ง
if (Actor->IsA<AMyCharacter>()) { }
// GetClass โ type_info ๋์ UClass ๋ฐํ
UClass* cls = Actor->GetClass();
FString name = cls->GetName(); // "MyCharacter"
|
**Cast vs dynamic_cast**:
| ย | dynamic_cast | Cast<T> (์ธ๋ฆฌ์ผ) |
|---|
| ๊ธฐ๋ฐ | C++ RTTI (vtable) | UObject ๋ฆฌํ๋ ์
(UClass) |
| UObject ์๋ ํ์
| ์ฌ์ฉ ๊ฐ๋ฅ | ์ฌ์ฉ ๋ถ๊ฐ |
| ์ฑ๋ฅ | vtable ํ์ | UClass ์ฒด์ธ ํ์ |
| ์คํจ ์ | nullptr | nullptr |
์ธ๋ฆฌ์ผ RAII โ FScopeLock, TGuardValue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // FScopeLock โ std::lock_guard ์ธ๋ฆฌ์ผ ๋ฒ์
FCriticalSection CriticalSection;
{
FScopeLock Lock(&CriticalSection); // ์์ฑ์: Lock(), ์๋ฉธ์: Unlock()
// ์๊ณ ๊ตฌ์ญ
} // ์๋ Unlock
// TGuardValue โ ์์ ๊ฐ ๋ณ๊ฒฝ ํ ์๋ ๋ณต์
bool bFlag = false;
{
TGuardValue<bool> Guard(bFlag, true); // bFlag = true
DoSomething();
} // bFlag = false ์๋ ๋ณต์
// FString, TArray โ ์๋ฉธ์์์ ํ ๋ฉ๋ชจ๋ฆฌ ์๋ ํด์ (RAII ์ ์ฉ)
FString Str = TEXT("Hello"); // ๋ด๋ถ์ ์ผ๋ก TArray<TCHAR> ์ฌ์ฉ
// Str ์๋ฉธ โ TArray ์๋ฉธ์ โ FMemory::Free ํธ์ถ
|
์ฐธ๊ณ