ํฌ์ŠคํŠธ

CS โ€” rtti raii

CS โ€” rtti raii

๐Ÿ“• 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 ์‹œ ํŒŒ์ƒ ์†Œ๋ฉธ์ž๊นŒ์ง€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒด์ธ ํ˜ธ์ถœ๋จ

๋ชฉ์ฐจ

  1. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ
  2. RTTI โ€” Runtime Type Information
  3. RAII โ€” Resource Acquisition Is Initialization
  4. ๊ผฌ๋ฆฌ์งˆ๋ฌธ ์˜ˆ์ƒ ๊ฒฝ๋กœ
  5. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ 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 โ†’ ๋™์  ๋””์ŠคํŒจ์น˜ (์ „๋‚  ์ฃผ์ œ ๋ณต์Šต)

2. RTTI โ€” Runtime Type Information

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

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_castdynamic_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_castCast<T> (์–ธ๋ฆฌ์–ผ)
๊ธฐ๋ฐ˜C++ RTTI (vtable)UObject ๋ฆฌํ”Œ๋ ‰์…˜ (UClass)
UObject ์•„๋‹Œ ํƒ€์ž…์‚ฌ์šฉ ๊ฐ€๋Šฅ์‚ฌ์šฉ ๋ถˆ๊ฐ€
์„ฑ๋Šฅvtable ํƒ์ƒ‰UClass ์ฒด์ธ ํƒ์ƒ‰
์‹คํŒจ ์‹œnullptrnullptr

์–ธ๋ฆฌ์–ผ 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 ํ˜ธ์ถœ

์ฐธ๊ณ 

์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

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

Powered by Jekyll with Chirpy theme

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