ํฌ์ŠคํŠธ

CS โ€” pointer deepdive

CS โ€” pointer deepdive

๐Ÿ“• ํฌ์ธํ„ฐยท๋ ˆํผ๋Ÿฐ์Šค ์‹ฌ์ธต ๋ถ„์„ โ€” ๋Œ•๊ธ€๋งยท๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐยท๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜

๊ธฐ๋ฐ˜ ํŒŒ์ผ: 07_pointer_reference.md ์ž‘์„ฑ ๊ธฐ์ค€: 2026-04-23 ๋ชจ์˜๋ฉด์ ‘ ์ถ”๊ฐ€ ๋ถ„์„


๋ชฉ์ฐจ

  1. ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ โ€” ์ž˜๋ชป๋œ ์ฃผ์†Œ ์ ‘๊ทผ
  2. ํฌ์ธํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ โ€” 32๋น„ํŠธ vs 64๋น„ํŠธ
  3. ๋ ˆํผ๋Ÿฐ์Šค์—์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์„๊นŒ?
  4. ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ๋ฐฉ์ง€ ํ‚ค์›Œ๋“œยทํŒจํ„ด
  5. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ
  6. ํ•ต์‹ฌ ์š”์•ฝ ์นด๋“œ

1. ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ โ€” ์ž˜๋ชป๋œ ์ฃผ์†Œ ์ ‘๊ทผ

Q: โ€œ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ๊ฐ€ ๋ฌด์—‡์ด๊ณ , ์–ด๋–ค ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•˜๋‚˜์š”?โ€

์ •์˜

๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ(Dangling Pointer): ํ•œ๋•Œ ์œ ํšจํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌ์ผฐ์œผ๋‚˜, ๊ทธ ๊ฐ์ฒด๊ฐ€ ํ•ด์ œ(freed) ๋˜๋Š” ์†Œ๋ฉธ(destroyed)๋œ ๋’ค์—๋„ ๋‚จ์•„ ์žˆ๋Š” ํฌ์ธํ„ฐ.

1
2
3
์œ ํšจํ•œ ํฌ์ธํ„ฐ:    p โ”€โ”€โ†’ [ 42 | ์‚ด์•„์žˆ๋Š” ๊ฐ์ฒด ]
ํ•ด์ œ ํ›„:          p โ”€โ”€โ†’ [ ?? | ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ ]  โ† ๋Œ•๊ธ€๋ง!
                         โ†‘ ์ด ์ฃผ์†Œ๋ฅผ ์—ญ์ฐธ์กฐํ•˜๋ฉด UB

๋ฐœ์ƒ ์‹œ๋‚˜๋ฆฌ์˜ค 3๊ฐ€์ง€

โ‘  delete ํ›„ ๋ฏธ์ดˆ๊ธฐํ™”

1
2
3
4
5
6
7
int* p = new int(42);
delete p;         // ํž™ ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ
// p๋Š” ์—ฌ์ „ํžˆ ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์Œ โ€” ๋Œ•๊ธ€๋ง!

*p = 10;          // ๐Ÿ’ฅ UB: ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ ์“ฐ๊ธฐ
std::cout << *p;  // ๐Ÿ’ฅ UB: ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ
delete p;         // ๐Ÿ’ฅ Double Free โ€” ํ”„๋กœ๊ทธ๋žจ ํฌ๋ž˜์‹œ

โ‘ก ์Šคํƒ ๋ณ€์ˆ˜ ์ฃผ์†Œ ๋ฐ˜ํ™˜

1
2
3
4
5
6
7
int* GetDangling() {
    int local = 42;   // ์Šคํƒ์— ํ• ๋‹น
    return &local;    // ํ•จ์ˆ˜ ์ข…๋ฃŒ ์‹œ local ์†Œ๋ฉธ
}                     // ์Šคํƒ ํ”„๋ ˆ์ž„ ํ•ด์ œ

int* p = GetDangling();
std::cout << *p;  // ๐Ÿ’ฅ UB: ์ด๋ฏธ ์†Œ๋ฉธ๋œ ์Šคํƒ ๋ณ€์ˆ˜

โ‘ข ์ปจํ…Œ์ด๋„ˆ ์žฌํ• ๋‹น ํ›„ ์ดํ„ฐ๋ ˆ์ดํ„ฐ/ํฌ์ธํ„ฐ

1
2
3
4
5
6
7
std::vector<int> v = {1, 2, 3};
int* p = &v[0];       // v ๋‚ด๋ถ€ ๋ฐฐ์—ด์˜ ์ฒซ ๋ฒˆ์งธ ์›์†Œ

v.push_back(4);       // ๐Ÿ’ฅ ๋‚ด๋ถ€ ๋ฐฐ์—ด ์žฌํ• ๋‹น ๋ฐœ์ƒ ๊ฐ€๋Šฅ
// p๋Š” ์ด์ œ ํ•ด์ œ๋œ ๊ตฌ ๋ฐฐ์—ด์„ ๊ฐ€๋ฆฌํ‚ด โ€” ๋Œ•๊ธ€๋ง!

std::cout << *p;      // UB

๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ์—ญ์ฐธ์กฐ ๊ฒฐ๊ณผ

์ƒํ™ฉ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ
์ฝ๊ธฐ์“ฐ๋ ˆ๊ธฐ ๊ฐ’ ๋ฐ˜ํ™˜, ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ
์“ฐ๊ธฐ๋‹ค๋ฅธ ๋ณ€์ˆ˜ ๋ฐ์ดํ„ฐ ์˜ค์—ผ, Heap ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์†์ƒ
Double Freeabort() / Segmentation Fault
์šด ์ข‹์€ ๊ฒฝ์šฐ์šฐ์—ฐํžˆ ์ •์ƒ ๋™์ž‘์ฒ˜๋Ÿผ ๋ณด์ž„ โ†’ ๋” ์œ„ํ—˜

ํ•ต์‹ฌ: ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ์—ญ์ฐธ์กฐ๋Š” Undefined Behavior โ€” ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๊ฐ€ ์—†๊ณ  ์ฆ‰์‹œ ํฌ๋ž˜์‹œ๋„ ์•ˆ ๋‚  ์ˆ˜ ์žˆ์–ด์„œ ๋””๋ฒ„๊น…์ด ๊ฐ€์žฅ ์–ด๋ ค์šด ๋ฒ„๊ทธ ์œ ํ˜•.


2. ํฌ์ธํ„ฐ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ โ€” 32๋น„ํŠธ vs 64๋น„ํŠธ

Q: โ€œํฌ์ธํ„ฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ช‡ ๋ฐ”์ดํŠธ ์ฐจ์ง€ํ•˜๋‚˜์š”?โ€

ํ•ต์‹ฌ ๋‹ต๋ณ€

ํฌ์ธํ„ฐ์˜ ํฌ๊ธฐ๋Š” ๊ณ ์ •์ด ์•„๋‹™๋‹ˆ๋‹ค. CPU ์ฃผ์†Œ ๋ฒ„์Šค ๋„ˆ๋น„(= ํ”Œ๋žซํผ์˜ ๋น„ํŠธ ์ˆ˜)์— ๋”ฐ๋ผ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

ํ”Œ๋žซํผํฌ์ธํ„ฐ ํฌ๊ธฐ์ด์œ 
32๋น„ํŠธ4๋ฐ”์ดํŠธ (32๋น„ํŠธ)์ฃผ์†Œ ๊ณต๊ฐ„ 2ยณยฒ = 4GB
64๋น„ํŠธ8๋ฐ”์ดํŠธ (64๋น„ํŠธ)์ฃผ์†Œ ๊ณต๊ฐ„ 2โถโด = 16 EB
1
2
3
4
5
6
7
8
9
10
// 64๋น„ํŠธ ํ”Œ๋žซํผ (ํ˜„๋Œ€ PC, ์ฝ˜์†”)
sizeof(int*)     // 8
sizeof(char*)    // 8
sizeof(void*)    // 8
sizeof(double*)  // 8
// ํฌ์ธํ„ฐ๋Š” ํƒ€์ž…(int, char, double)๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋ชจ๋‘ ๊ฐ™์€ ํฌ๊ธฐ

// 32๋น„ํŠธ ํ”Œ๋žซํผ (์ž„๋ฒ ๋””๋“œ, ๊ตฌํ˜• ์‹œ์Šคํ…œ)
sizeof(int*)     // 4
sizeof(void*)    // 4

์™œ ํƒ€์ž…์— ์ƒ๊ด€์—†์ด ํฌ๊ธฐ๊ฐ€ ๊ฐ™์€๊ฐ€?

ํฌ์ธํ„ฐ๊ฐ€ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ โ€œ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด์˜ ํƒ€์ž… ์ •๋ณดโ€๊ฐ€ ์•„๋‹ˆ๋ผ โ€œ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œโ€์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋Š” ํ”Œ๋žซํผ์˜ ์ฃผ์†Œ ๋ฒ„์Šค ๋„ˆ๋น„๋กœ ๊ณ ์ •๋˜๋ฏ€๋กœ, int*๋“  double*๋“  ์ €์žฅํ•˜๋Š” ๊ฐ’(์ฃผ์†Œ)์˜ ํฌ๊ธฐ๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

1
2
3
4
5
6
7
int    x = 10;
double d = 3.14;

int*    pi = &x;   // ์ฃผ์†Œ ์ €์žฅ: 8๋ฐ”์ดํŠธ (64๋น„ํŠธ)
double* pd = &d;   // ์ฃผ์†Œ ์ €์žฅ: 8๋ฐ”์ดํŠธ (64๋น„ํŠธ)
// pi์™€ pd๊ฐ€ ์ €์žฅํ•˜๋Š” "์ฃผ์†Œ ๊ฐ’"์˜ ํฌ๊ธฐ๋Š” ๋™์ผ
// ์ฐจ์ด๋Š” ์—ญ์ฐธ์กฐ ์‹œ ์ฝ๋Š” ๋ฐ”์ดํŠธ ์ˆ˜ (int: 4, double: 8)

vptr๋„ ํฌ์ธํ„ฐ ํฌ๊ธฐ๋ฅผ ๋”ฐ๋ฅธ๋‹ค

virtual ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค ๊ฐ์ฒด ๋งจ ์•ž์— ์‚ฝ์ž…๋˜๋Š” vptr๋„ ๋™์ผํ•˜๊ฒŒ ํ”Œ๋žซํผ ํฌ์ธํ„ฐ ํฌ๊ธฐ๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

1
2
3
4
5
6
class Base {
    virtual void Foo() {}
    int x;
};
// 64๋น„ํŠธ: sizeof(Base) = 8(vptr) + 4(int) + 4(padding) = 16
// 32๋น„ํŠธ: sizeof(Base) = 4(vptr) + 4(int)             =  8

๋ ˆํผ๋Ÿฐ์Šค์˜ ํฌ๊ธฐ

๋ ˆํผ๋Ÿฐ์Šค ์ž์ฒด์˜ ํฌ๊ธฐ๋ฅผ sizeof๋กœ ์ธก์ •ํ•˜๋ฉด ์›๋ณธ ๊ฐ์ฒด์˜ ํฌ๊ธฐ๊ฐ€ ๋‚˜์˜ต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ํฌ์ธํ„ฐ๋กœ ๊ตฌํ˜„ํ•˜๋”๋ผ๋„ ์–ธ์–ด ์ˆ˜์ค€์—์„œ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

1
2
3
4
int x = 10;
int& r = x;
sizeof(r);   // sizeof(int) = 4  โ€” ํฌ์ธํ„ฐ 8์ด ์•„๋‹˜!
             // r์€ x์˜ ๋ณ„์นญ์ด๋ฏ€๋กœ sizeof๊ฐ€ x์˜ ํฌ๊ธฐ๋ฅผ ๋ฐ˜ํ™˜

30์ดˆ ๋‹ต๋ณ€:
ํฌ์ธํ„ฐ ํฌ๊ธฐ๋Š” ํ”Œ๋žซํผ์˜ ๋น„ํŠธ ์ˆ˜์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. 64๋น„ํŠธ ์‹œ์Šคํ…œ์—์„œ๋Š” 8๋ฐ”์ดํŠธ, 32๋น„ํŠธ ์‹œ์Šคํ…œ์—์„œ๋Š” 4๋ฐ”์ดํŠธ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํฌ์ธํ„ฐ๊ฐ€ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ํƒ€์ž…์ด ์•„๋‹Œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์˜ ํฌ๊ธฐ๊ฐ€ CPU ์ฃผ์†Œ ๋ฒ„์Šค ๋„ˆ๋น„๋กœ ๊ฒฐ์ •๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


3. ๋ ˆํผ๋Ÿฐ์Šค์—์„œ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์„๊นŒ?

Q: โ€œ๋ ˆํผ๋Ÿฐ์Šค๋Š” ํ•ญ์ƒ ์•ˆ์ „ํ•œ๊ฐ€์š”? ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‚˜์š”?โ€

์งง์€ ๋‹ต๋ณ€: ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ ์ปดํŒŒ์ผ ํƒ€์ž„์—๋Š” ์žกํžˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ ˆํผ๋Ÿฐ์Šค๋Š” ๋ฌธ๋ฒ•์ ์œผ๋กœ ํ•ญ์ƒ ์œ ํšจํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•˜์ง€๋งŒ, ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ๊ทœ์น™์„ ์–ด๊ธฐ๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.


์ผ€์ด์Šค 1 โ€” ๋Œ•๊ธ€๋ง ๋ ˆํผ๋Ÿฐ์Šค (Dangling Reference)

1
2
3
4
5
6
7
int& GetDangling() {
    int local = 42;
    return local;    // โš ๏ธ ์ปดํŒŒ์ผ ๊ฒฝ๊ณ  ๋ฐœ์ƒ
}                    // local ์†Œ๋ฉธ!

int& r = GetDangling();
std::cout << r;  // ๐Ÿ’ฅ UB: ์ด๋ฏธ ์†Œ๋ฉธ๋œ ์Šคํƒ ๋ณ€์ˆ˜๋ฅผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ์ ‘๊ทผ

์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๊ฒฝ๊ณ ๋Š” ํ•˜์ง€๋งŒ ์˜ค๋ฅ˜๋Š” ์•„๋‹˜ โ†’ ๋Ÿฐํƒ€์ž„ UB.


์ผ€์ด์Šค 2 โ€” nullptr ์—ญ์ฐธ์กฐ ํ›„ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ๋ณ€ํ™˜

1
2
3
4
5
int* p = nullptr;
int& r = *p;     // ์ปดํŒŒ์ผ OK โ€” ๋ฌธ๋ฒ•์ ์œผ๋กœ ํ—ˆ์šฉ
                 // ์‹ค์ œ ์—ญ์ฐธ์กฐ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์‹œ์ ์— ๋”ฐ๋ผ UB

std::cout << r;  // ๐Ÿ’ฅ Segmentation Fault

*p๊ฐ€ null ์—ญ์ฐธ์กฐ์ด์ง€๋งŒ ๋ ˆํผ๋Ÿฐ์Šค ๋ฐ”์ธ๋”ฉ ๋ฌธ๋ฒ•์ด ๊ฐ€๋ ค์ค๋‹ˆ๋‹ค.


์ผ€์ด์Šค 3 โ€” ์ปจํ…Œ์ด๋„ˆ ์žฌํ• ๋‹น ํ›„ ๋ ˆํผ๋Ÿฐ์Šค

1
2
3
4
5
std::vector<int> v = {1, 2, 3};
int& ref = v[0];      // v ๋‚ด๋ถ€ ์›์†Œ ๋ ˆํผ๋Ÿฐ์Šค

v.push_back(100);     // ์žฌํ• ๋‹น ๋ฐœ์ƒ โ†’ ref๊ฐ€ ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ
std::cout << ref;     // ๐Ÿ’ฅ UB: ๋Œ•๊ธ€๋ง ๋ ˆํผ๋Ÿฐ์Šค

ํฌ์ธํ„ฐ์™€ ์™„์ „ํžˆ ๋™์ผํ•œ ๋ฌธ์ œ โ€” ๋ ˆํผ๋Ÿฐ์Šค๋„ ํ”ผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.


์ผ€์ด์Šค 4 โ€” ์ˆ˜๋ช…์ด ๋๋‚œ ์ž„์‹œ ๊ฐ์ฒด ๋ ˆํผ๋Ÿฐ์Šค

1
2
3
4
5
const int& r = 42;      // โœ… const ๋ ˆํผ๋Ÿฐ์Šค โ€” ์ž„์‹œ ๊ฐ์ฒด ์ˆ˜๋ช… ์—ฐ์žฅ (C++ ๊ทœ์น™)
// r์˜ ์ˆ˜๋ช…์ด ๋๋‚  ๋•Œ๊นŒ์ง€ 42 ์œ ํšจ

int& r2 = someFunc();   // someFunc()์ด int& ๋ฐ˜ํ™˜ ์‹œ
                        // ๋ฐ˜ํ™˜๋œ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋‚ด๋ถ€ ์ง€์—ญ๋ณ€์ˆ˜๋ฉด ๋Œ•๊ธ€๋ง!

๋ ˆํผ๋Ÿฐ์Šค์™€ ํฌ์ธํ„ฐ์˜ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋น„๊ต

ย ํฌ์ธํ„ฐ๋ ˆํผ๋Ÿฐ์Šค
nullptr ๊ฐ€๋Šฅโœ… (๋ช…์‹œ์ )โŒ (๋ฌธ๋ฒ• ๋ถˆ๊ฐ€, ๋‹จ ์šฐํšŒ ๊ฐ€๋Šฅ)
๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅโœ…โœ… (๋Œ•๊ธ€๋ง, nullptr ์šฐํšŒ)
์ปดํŒŒ์ผ ํƒ€์ž„ ๊ฐ์ง€์ผ๋ถ€์ผ๋ถ€ ๊ฒฝ๊ณ 
์žฌํ• ๋‹น ํ›„ ๋ฌดํšจํ™”โœ…โœ… (๋™์ผํ•˜๊ฒŒ ๋ฐœ์ƒ)

30์ดˆ ๋‹ต๋ณ€:
๋ ˆํผ๋Ÿฐ์Šค๋„ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ์ผ€์ด์Šค๋Š” ์„ธ ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์ฒซ์งธ, ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ•จ์ˆ˜ ์ข…๋ฃŒ ํ›„ ๋Œ•๊ธ€๋ง ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋‘˜์งธ, int& r = *nullptr ๊ฐ™์ด null ํฌ์ธํ„ฐ๋ฅผ ์—ญ์ฐธ์กฐํ•ด์„œ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ๋ฐ”์ธ๋”ฉํ•˜๋ฉด UB๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์…‹์งธ, vector ์žฌํ• ๋‹น ํ›„ ๊ธฐ์กด ์›์†Œ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ๋ฌดํšจํ™”๋ฉ๋‹ˆ๋‹ค. ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ โ€œํ•ญ์ƒ ์•ˆ์ „ํ•˜๋‹คโ€๋Š” ๊ฒƒ์€ ๋ฌธ๋ฒ•์  ์ œ์•ฝ์ด์ง€, ๋Ÿฐํƒ€์ž„ ์•ˆ์ „์„ ๋ณด์žฅํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.


4. ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ๋ฐฉ์ง€ ํ‚ค์›Œ๋“œยทํŒจํ„ด

Q: โ€œ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ๊ฐ€์š”?โ€

โ‘  delete ํ›„ ์ฆ‰์‹œ nullptr ์ดˆ๊ธฐํ™”

1
2
3
4
5
6
7
int* p = new int(42);
delete p;
p = nullptr;          // โ† ๋Œ•๊ธ€๋ง ๋ฐฉ์ง€์˜ ์ตœ์†Œ ๋ฐฉ์–ด์„ 

if (p != nullptr) {   // nullptr ์ฒดํฌ๊ฐ€ ์ด์ œ ์˜๋ฏธ ์žˆ์–ด์ง
    *p = 10;
}

ํ•œ๊ณ„: Double Free๋Š” ๋ฐฉ์ง€ํ•˜์ง€๋งŒ ์ด๋ฏธ ๊ฐ™์€ ์ฃผ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋‹ค๋ฅธ ํฌ์ธํ„ฐ(alias)๋Š” ์—ฌ์ „ํžˆ ๋Œ•๊ธ€๋ง.


โ‘ก unique_ptr โ€” ์†Œ์œ ๊ถŒ ๋‹จ๋…ํ™”๋กœ Double Free ์›์ฒœ ์ฐจ๋‹จ

1
2
3
4
5
6
7
auto p = std::make_unique<int>(42);
// delete ๋ถˆํ•„์š” โ€” ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ ์‹œ ์ž๋™ ํ•ด์ œ
// unique_ptr์ด ์†Œ๋ฉธ๋˜๋ฉด ๋‚ด๋ถ€ ํฌ์ธํ„ฐ๋„ ์ž๋™ nullptr

// unique_ptr๋Š” ๋ณต์‚ฌ ๋ถˆ๊ฐ€ โ†’ ๋‘ ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ™์€ ๊ฐ์ฒด ์†Œ์œ  ๋ถˆ๊ฐ€
auto p2 = p;  // โŒ ์ปดํŒŒ์ผ ์˜ค๋ฅ˜
auto p3 = std::move(p);  // โœ… ์†Œ์œ ๊ถŒ ์ด์ „, p๋Š” nullptr

โ‘ข shared_ptr + weak_ptr โ€” ์ˆ˜๋ช… ์ถ”์ 

1
2
3
4
5
6
7
8
9
auto shared = std::make_shared<int>(42);
std::weak_ptr<int> weak = shared;   // ์†Œ์œ ๊ถŒ ์—†์ด ๊ด€์ฐฐ

// ์•ˆ์ „ํ•œ ์ ‘๊ทผ ํŒจํ„ด
if (auto locked = weak.lock()) {    // shared_ptr ์ž„์‹œ ํš๋“
    std::cout << *locked;           // ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ ‘๊ทผ
} else {
    // ์ด๋ฏธ ํ•ด์ œ๋จ
}

weak_ptr::lock()์€ ์›๋ณธ์ด ์‚ด์•„์žˆ์œผ๋ฉด shared_ptr๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ด๋ฏธ ํ•ด์ œ๋์œผ๋ฉด nullptr๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ์ „ํ•œ ๋Œ•๊ธ€๋ง ๊ฐ์ง€ ํŒจํ„ด.


โ‘ฃ std::optional โ€” โ€œ์—†์„ ์ˆ˜๋„ ์žˆ๋Š” ๊ฐ’โ€ ๋ช…์‹œ

1
2
3
4
5
6
7
8
9
10
11
// ํฌ์ธํ„ฐ ๋Œ€์‹  optional ์‚ฌ์šฉ โ€” ๋Œ•๊ธ€๋ง ์ž์ฒด๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ์ œ๊ฑฐ
std::optional<int> Find(const std::vector<int>& v, int target) {
    for (int x : v)
        if (x == target) return x;   // ๊ฐ’ ๋ฐ˜ํ™˜
    return std::nullopt;             // ์—†์Œ ๋ช…์‹œ
}

auto result = Find(vec, 42);
if (result.has_value()) {
    std::cout << *result;            // ์•ˆ์ „
}

ํฌ์ธํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๊ฐ€ โ€œ์—†์„ ์ˆ˜๋„ ์žˆ์–ด์„œโ€๋ผ๋ฉด optional์ด ๋” ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.


โ‘ค RAII ํŒจํ„ด โ€” ๊ฐ์ฒด ์ˆ˜๋ช…๊ณผ ์ž์› ์ˆ˜๋ช… ๋™๊ธฐํ™”

1
2
3
4
5
6
7
8
9
10
11
12
// ์ž˜๋ชป๋œ ํŒจํ„ด โ€” ์ˆ˜๋ช… ๋ถˆ์ผ์น˜
{
    int* p = new int(42);
    // ... ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ delete ์•ˆ ๋จ
    delete p;  // ๋„๋‹ฌ ๋ชป ํ•  ์ˆ˜๋„ ์žˆ์Œ
}

// RAII ํŒจํ„ด โ€” ์Šค์ฝ”ํ”„์™€ ์ˆ˜๋ช… ๋™๊ธฐํ™”
{
    auto p = std::make_unique<int>(42);
    // ์˜ˆ์™ธ ๋ฐœ์ƒํ•ด๋„ unique_ptr ์†Œ๋ฉธ์ž๊ฐ€ delete ๋ณด์žฅ
}   // ์ž๋™ ํ•ด์ œ

โ‘ฅ ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๊ณ  + Sanitizer

1
2
3
4
5
# Address Sanitizer โ€” ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ ์—ญ์ฐธ์กฐ๋ฅผ ๋Ÿฐํƒ€์ž„์— ์ฆ‰์‹œ ๊ฐ์ง€
clang++ -fsanitize=address -g main.cpp

# ์ปดํŒŒ์ผ๋Ÿฌ ๊ฒฝ๊ณ  ํ™œ์„ฑํ™”
g++ -Wall -Wextra -Wnull-dereference
1
2
3
4
# AddressSanitizer ์ถœ๋ ฅ ์˜ˆ์‹œ
ERROR: AddressSanitizer: heap-use-after-free on address 0x... 
READ of size 4 at 0x... thread T0
    #0 0x... in main main.cpp:8

๋ฐฉ์ง€ ์ „๋žต ์š”์•ฝ

๋ฐฉ๋ฒ•๋ฐฉ์ง€ํ•˜๋Š” ์ผ€์ด์Šค๋น„์šฉ
delete ํ›„ = nullptrDouble Free ๋ฐฉ์ง€์—†์Œ
unique_ptr์†Œ์œ ๊ถŒ ๋‹จ๋…ํ™”, Double Free๊ฑฐ์˜ ์—†์Œ
shared_ptr + weak_ptr์ˆ˜๋ช… ๊ณต์œ  + ๋Œ•๊ธ€๋ง ๊ฐ์ง€์ฐธ์กฐ ์นด์šดํŒ… ๋น„์šฉ
std::optionalโ€œ์—†์„ ์ˆ˜๋„โ€ ์ผ€์ด์Šค์—†์Œ
RAII ํŒจํ„ด์˜ˆ์™ธ ๊ฒฝ๋กœ ๋ˆ„์ˆ˜์—†์Œ
AddressSanitizer๋Ÿฐํƒ€์ž„ ๊ฐ์ง€ (๊ฐœ๋ฐœ์šฉ)์„ฑ๋Šฅ ์ €ํ•˜ (ํ”„๋กœ๋•์…˜ ๋ฏธ์‚ฌ์šฉ)

5. ์–ธ๋ฆฌ์–ผ์—์„œ์˜ ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ

UPROPERTY ์—†๋Š” UObject ํฌ์ธํ„ฐ = ๋Œ•๊ธ€๋ง ์œ„ํ—˜

1
2
3
4
5
6
7
8
9
10
11
UCLASS()
class AMyActor : public AActor {
    GENERATED_BODY()

    // โŒ UPROPERTY ์—†์Œ โ†’ GC๊ฐ€ ์ด ํฌ์ธํ„ฐ๋ฅผ ์ถ”์ ํ•˜์ง€ ์•Š์Œ
    UMyComponent* DangerousComp;

    // โœ… UPROPERTY ์žˆ์Œ โ†’ GC ์ถ”์ , ์ˆ˜๊ฑฐ ์ „์— nullptr ์„ธํŒ…
    UPROPERTY()
    UMyComponent* SafeComp;
};

GC๊ฐ€ UMyComponent ์ธ์Šคํ„ด์Šค๋ฅผ ์ˆ˜๊ฑฐํ•˜๋ฉด:

  • UPROPERTY ์žˆ๋Š” ํฌ์ธํ„ฐ โ†’ GC๊ฐ€ ์ž๋™์œผ๋กœ nullptr ์„ธํŒ… (๋Œ•๊ธ€๋ง ๋ฐฉ์ง€)
  • UPROPERTY ์—†๋Š” ํฌ์ธํ„ฐ โ†’ ์ˆ˜๊ฑฐ ํ›„์—๋„ ํฌ์ธํ„ฐ ๊ฐ’ ์œ ์ง€ โ†’ ๋Œ•๊ธ€๋ง!

IsValid() / IsValidLowLevel()

1
2
3
4
5
6
7
8
9
// ์–ธ๋ฆฌ์–ผ์—์„œ UObject ํฌ์ธํ„ฐ ์•ˆ์ „ ์ ‘๊ทผ ํŒจํ„ด
if (IsValid(SafeComp)) {       // nullptr ์ฒดํฌ + ๊ฐ€๋น„์ง€ ๋งˆํ‚น ์ฒดํฌ
    SafeComp->DoSomething();
}

// nullptr ์ฒดํฌ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑ
if (SafeComp != nullptr) {     // โš ๏ธ GC Mark๋์ง€๋งŒ ์•„์ง ์ˆ˜๊ฑฐ ์•ˆ ๋œ ๊ฒฝ์šฐ ํ†ต๊ณผ
    SafeComp->DoSomething();   // ํฌ๋ž˜์‹œ ๊ฐ€๋Šฅ
}

TWeakObjectPtr โ€” ์–ธ๋ฆฌ์–ผ์˜ weak_ptr

1
2
3
4
5
6
7
TWeakObjectPtr<UMyComponent> WeakComp;

// ์•ˆ์ „ํ•œ ์ ‘๊ทผ
if (WeakComp.IsValid()) {
    UMyComponent* Comp = WeakComp.Get();
    Comp->DoSomething();
}

GC๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ˆ˜๊ฑฐํ•˜๋ฉด TWeakObjectPtr๋Š” ์ž๋™์œผ๋กœ invalid ์ƒํƒœ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. C++ weak_ptr์˜ ์–ธ๋ฆฌ์–ผ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.


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

๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ 30์ดˆ

1
2
3
4
5
6
7
8
๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ = ํ•ด์ œ๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ
3๋Œ€ ๋ฐœ์ƒ ์›์ธ:
  1. delete ํ›„ ๋ฏธ์ดˆ๊ธฐํ™”
  2. ์Šคํƒ ๋ณ€์ˆ˜ ์ฃผ์†Œ ๋ฐ˜ํ™˜
  3. ์ปจํ…Œ์ด๋„ˆ ์žฌํ• ๋‹น ํ›„ ์ดํ„ฐ๋ ˆ์ดํ„ฐ/ํฌ์ธํ„ฐ

๊ฒฐ๊ณผ: UB โ€” ์“ฐ๋ ˆ๊ธฐ ๊ฐ’, ๋ฉ”๋ชจ๋ฆฌ ์˜ค์—ผ, Double Free, Segfault
๋ฐฉ์ง€: delete ํ›„ nullptr / unique_ptr / RAII / AddressSanitizer

ํฌ์ธํ„ฐ ํฌ๊ธฐ 30์ดˆ

1
2
3
4
5
6
ํฌ์ธํ„ฐ ํฌ๊ธฐ = CPU ์ฃผ์†Œ ๋ฒ„์Šค ๋„ˆ๋น„
  32๋น„ํŠธ ์‹œ์Šคํ…œ: 4๋ฐ”์ดํŠธ (์ฃผ์†Œ ๊ณต๊ฐ„ 4GB)
  64๋น„ํŠธ ์‹œ์Šคํ…œ: 8๋ฐ”์ดํŠธ (์ฃผ์†Œ ๊ณต๊ฐ„ 16EB)

ํƒ€์ž…(int*, double*)๊ณผ ๋ฌด๊ด€ โ€” ์ €์žฅํ•˜๋Š” ๊ฐ’์ด "์ฃผ์†Œ"์ด๊ธฐ ๋•Œ๋ฌธ
sizeof(๋ ˆํผ๋Ÿฐ์Šค) = ์›๋ณธ ๊ฐ์ฒด ํฌ๊ธฐ (ํฌ์ธํ„ฐ ํฌ๊ธฐ ์•„๋‹˜)

๋ ˆํผ๋Ÿฐ์Šค ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ 30์ดˆ

1
2
3
4
5
6
๋ ˆํผ๋Ÿฐ์Šค๋„ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ:
  1. ์ง€์—ญ ๋ณ€์ˆ˜ ๋ ˆํผ๋Ÿฐ์Šค ๋ฐ˜ํ™˜ โ†’ ๋Œ•๊ธ€๋ง ๋ ˆํผ๋Ÿฐ์Šค
  2. int& r = *nullptr โ†’ null ์—ญ์ฐธ์กฐ UB
  3. vector ์žฌํ• ๋‹น ํ›„ ๊ธฐ์กด ์›์†Œ ๋ ˆํผ๋Ÿฐ์Šค โ†’ ๋Œ•๊ธ€๋ง

"๋ ˆํผ๋Ÿฐ์Šค๋Š” ํ•ญ์ƒ ์•ˆ์ „" = ๋ฌธ๋ฒ• ์ œ์•ฝ, ๋Ÿฐํƒ€์ž„ ์•ˆ์ „ ๋ณด์žฅ ์•„๋‹˜

๋Œ•๊ธ€๋ง ๋ฐฉ์ง€ ํ‚ค์›Œ๋“œ

1
2
3
4
5
6
7
nullptr    โ€” delete ํ›„ ์ฆ‰์‹œ = nullptr
unique_ptr โ€” ์†Œ์œ ๊ถŒ ๋‹จ๋…ํ™”, Double Free ์›์ฒœ ์ฐจ๋‹จ
weak_ptr   โ€” ์ˆ˜๋ช… ์ถ”์ , lock()์œผ๋กœ ์•ˆ์ „ ์ ‘๊ทผ
optional   โ€” "์—†์„ ์ˆ˜๋„"๋ฅผ ํฌ์ธํ„ฐ ์—†์ด ํ‘œํ˜„
RAII       โ€” ์Šค์ฝ”ํ”„์™€ ์ž์› ์ˆ˜๋ช… ๋™๊ธฐํ™”
IsValid()  โ€” ์–ธ๋ฆฌ์–ผ: nullptr + GC ๋งˆํ‚น ๋™์‹œ ์ฒดํฌ
UPROPERTY  โ€” ์–ธ๋ฆฌ์–ผ: GC ์ถ”์  ๋“ฑ๋ก (์—†์œผ๋ฉด ๋Œ•๊ธ€๋ง)

์ฐธ๊ณ 

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

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

Powered by Jekyll with Chirpy theme

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