ํฌ์ŠคํŠธ

CS โ€” new vs malloc

CS โ€” new vs malloc

๐Ÿ“• new์™€ malloc์˜ ์ฐจ์ด์ 

Notion ์›๋ณธ: https://www.notion.so/344f77b24d2f806baae6efa26094f26f ๋ถ€๋ชจ: ์ž๋ฃŒ โ†’ Cs ๋ฉด์ ‘์ค€๋น„ โ†’ cs ์ฃผ์ œ

30์ดˆ ๋‹ต๋ณ€

new๋Š” C++ ์—ฐ์‚ฐ์ž๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น + ์ƒ์„ฑ์ž ํ˜ธ์ถœ์„ ํ•จ๊ป˜ ์ˆ˜ํ–‰ํ•˜๊ณ , ์‹คํŒจ ์‹œ std::bad_alloc ์˜ˆ์™ธ๋ฅผ throwํ•ฉ๋‹ˆ๋‹ค. malloc์€ C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋กœ raw ๋ฉ”๋ชจ๋ฆฌ๋งŒ ํ• ๋‹นํ•˜๊ณ , ์‹คํŒจ ์‹œ NULL์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. C++ ๊ฐ์ฒด์—๋Š” ๋ฐ˜๋“œ์‹œ new/delete๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, ๋‘ ๋ฐฉ์‹์„ ์ ˆ๋Œ€ ํ˜ผ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ์ฐจ์ด 4๊ฐ€์ง€

#ํ•ญ๋ชฉnewmalloc
1๋ถ„๋ฅ˜C++ ์—ฐ์‚ฐ์ž (operator)C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜
2์ƒ์„ฑ์ž/์†Œ๋ฉธ์žํ˜ธ์ถœ Oํ˜ธ์ถœ X (raw ๋ฉ”๋ชจ๋ฆฌ)
3์‹คํŒจ ์ฒ˜๋ฆฌstd::bad_alloc throwNULL ๋ฐ˜ํ™˜
4ํƒ€์ž… ์•ˆ์ „์„ฑํƒ€์ž… ์ž๋™ ์ง€์ •void* โ†’ ์บ์ŠคํŒ… ํ•„์š”
+์˜ค๋ฒ„๋กœ๋”ฉ / ํ•ด์ œ๊ฐ€๋Šฅ / delete๋ถˆ๊ฐ€ / free()

๋ฉด์ ‘์šฉ ์ตœ์†Œ ์ฝ”๋“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
class Player {
public:
    Player()  { cout << "์ƒ์„ฑ์ž"; }
    ~Player() { cout << "์†Œ๋ฉธ์ž"; }
};

// new โ€” ์ƒ์„ฑ์ž/์†Œ๋ฉธ์ž ํ˜ธ์ถœ๋จ โœ…
Player* p1 = new Player();   // "์ƒ์„ฑ์ž"
delete p1;                   // "์†Œ๋ฉธ์ž"

// malloc โ€” ํ˜ธ์ถœ ์•ˆ ๋จ โ†’ UB ์œ„ํ—˜ โš ๏ธ
Player* p2 = (Player*)malloc(sizeof(Player));
free(p2);   // ์ดˆ๊ธฐํ™” X, ์†Œ๋ฉธ์ž X, ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜

๊ผฌ๋ฆฌ์งˆ๋ฌธ ๋Œ€์‘ ๋ธŒ๋žœ์น˜

  • โ€œmalloc์œผ๋กœ C++ ๊ฐ์ฒด ๋งŒ๋“ค๋ฉด?โ€ โ†’ UB. ์ƒ์„ฑ์ž ํ˜ธ์ถœ ์•ˆ ๋จ โ†’ ๋ฉค๋ฒ„ ์ดˆ๊ธฐํ™” ์•ˆ ๋จ + ์†Œ๋ฉธ์ž ํ˜ธ์ถœ ์•ˆ ๋จ โ†’ ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜
  • โ€œC++์—์„œ malloc ์•„์˜ˆ ๋ชป ์”€?โ€ โ†’ POD ํƒ€์ž…(int/char ๋“ฑ)์—” ๊ธฐ์ˆ ์  ๊ฐ€๋Šฅ. ์ผ๊ด€์„ฑ ์œ„ํ•ด new/delete ๋˜๋Š” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ ๊ถŒ์žฅ
  • โ€œnew (nothrow)๊ฐ€ ๋ญ?โ€ โ†’ ์˜ˆ์™ธ ๋Œ€์‹  NULL ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฒ„์ „. new(nothrow) int[N] โ†’ nullptr ์ฒดํฌ
  • โ€œ๋Œ€์‹  ๋ญ˜ ์จ์•ผ?โ€ โ†’ ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ โ€” unique_ptr / shared_ptr / make_unique
  • โ€œnew ๋‚ด๋ถ€ ๋™์ž‘?โ€ โ†’ 2๋‹จ๊ณ„ โ€” โ‘  operator new๋กœ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น โ†’ โ‘ก ์ƒ์„ฑ์ž ํ˜ธ์ถœ
  • โ€œoperator new ์˜ค๋ฒ„๋กœ๋”ฉ?โ€ โ†’ ํด๋ž˜์Šค๋ณ„ ์ปค์Šคํ…€ ํ• ๋‹น ๊ฐ€๋Šฅ. ์–ธ๋ฆฌ์–ผ UObject๊ฐ€ ๋Œ€ํ‘œ ์‚ฌ๋ก€ (GC ํ’€ ํ• ๋‹น)
  • โ€œplacement new?โ€ โ†’ ์ด๋ฏธ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ์œ„์— ์ƒ์„ฑ์ž๋งŒ ํ˜ธ์ถœ. ํ•ด์ œ ์‹œ ์†Œ๋ฉธ์ž ์ง์ ‘ ํ˜ธ์ถœ (p->~T())
  • โ€œํ˜ผ์šฉํ•˜๋ฉด ์™œ UB?โ€ โ†’ new / malloc ์€ ๋‚ด๋ถ€ ํ• ๋‹น์ž๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Œ โ†’ ํ•ด์ œ ์Œ์ด ์•ˆ ๋งž์œผ๋ฉด ํž™ ์†์ƒ
  • โ€œ์†Œ๋ฉธ์ž ์™œ virtual?โ€ โ†’ ๊ธฐ๋ฐ˜ ํฌ์ธํ„ฐ๋กœ delete ์‹œ ํŒŒ์ƒ ์†Œ๋ฉธ์ž ํ˜ธ์ถœ ๋ณด์žฅ (vtable ๋™์  ๋””์ŠคํŒจ์น˜)

ํ‚ค์›Œ๋“œ๋ณ„ 30์ดˆ ๋‹ต๋ณ€

operator new (์˜ค๋ฒ„๋กœ๋”ฉ)

  • ํ•จ์ˆ˜์ด๋ฏ€๋กœ ํด๋ž˜์Šค๋ณ„/์ „์—ญ ์˜ค๋ฒ„๋กœ๋”ฉ ๊ฐ€๋Šฅ
  • new ํ‘œํ˜„์‹ = operator new(๋ฉ”๋ชจ๋ฆฌ) + ์ƒ์„ฑ์ž ํ˜ธ์ถœ 2๋‹จ๊ณ„
  • ์ง์ ‘ ํ˜ธ์ถœ ์‹œ raw ๋ฉ”๋ชจ๋ฆฌ๋งŒ ํ• ๋‹น โ†’ malloc๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ ์‹คํŒจ ์‹œ ์˜ˆ์™ธ
  • ์–ธ๋ฆฌ์–ผ UObject๊ฐ€ ๋Œ€ํ‘œ ์‚ฌ๋ก€ โ€” GC ๊ด€๋ฆฌ ํ’€์—์„œ ํ• ๋‹น
1
2
3
4
class Bullet {
    static void* operator new(size_t s) { return PoolAllocator::alloc(s); }
    static void operator delete(void* p) { /* ํ’€์€ ๊ฐœ๋ณ„ ํ•ด์ œ ์•ˆ ํ•จ */ }
};

placement new

  • ์ด๋ฏธ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ์œ„์— ๊ฐ์ฒด ์ƒ์„ฑ
  • ๋ฉ”๋ชจ๋ฆฌ ์žฌํ• ๋‹น ์—†์ด ์ƒ์„ฑ์ž๋งŒ ํ˜ธ์ถœ
  • ํ•ด์ œ ์‹œ delete ๋Œ€์‹  ์†Œ๋ฉธ์ž ์ง์ ‘ ํ˜ธ์ถœ p->~T()
  • ๋ฉ”๋ชจ๋ฆฌ ํ’€ / ์žฌ์‚ฌ์šฉ ๋ฒ„ํผ์— ์‚ฌ์šฉ
1
2
3
char buf[sizeof(Player)];
Player* p = new(buf) Player();
p->~Player();   // ์†Œ๋ฉธ์ž ์ง์ ‘ ํ˜ธ์ถœ

UB (Undefined Behavior)

  • malloc + C++ ๊ฐ์ฒด โ†’ ์ƒ์„ฑ์ž ํ˜ธ์ถœ X โ†’ ๋ฉค๋ฒ„ ๋ฏธ์ดˆ๊ธฐํ™”
  • free + C++ ๊ฐ์ฒด โ†’ ์†Œ๋ฉธ์ž ํ˜ธ์ถœ X โ†’ ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜
  • new + free / malloc + delete ํ˜ผ์šฉ โ†’ ํž™ ์†์ƒ

์Šค๋งˆํŠธ ํฌ์ธํ„ฐ (C++11+ ๊ถŒ์žฅ)

ย unique_ptrshared_ptr
์†Œ์œ ๊ถŒ๋‹จ๋…๊ณต์œ  (์ฐธ์กฐ ์นด์šดํŒ…)
๋ณต์‚ฌ๋ถˆ๊ฐ€ (์ด๋™๋งŒ)๊ฐ€๋Šฅ
์˜ค๋ฒ„ํ—ค๋“œ์—†์Œref count ๋น„์šฉ
ํ•ด์ œ์Šค์ฝ”ํ”„ ์ข…๋ฃŒ๋งˆ์ง€๋ง‰ shared ์†Œ๋ฉธ
1
2
auto p1 = make_unique<Player>();
auto p2 = make_shared<Player>();

virtual ์†Œ๋ฉธ์ž

  • ๊ธฐ๋ฐ˜ ํฌ์ธํ„ฐ๋กœ ํŒŒ์ƒ ๊ฐ์ฒด๋ฅผ deleteํ•  ๋•Œ ๋ฐ˜๋“œ์‹œ ํ•„์š”
  • ์†Œ๋ฉธ์ž๊ฐ€ ์ผ๋ฐ˜ ํ•จ์ˆ˜๋ฉด โ†’ ๊ธฐ๋ฐ˜ ์†Œ๋ฉธ์ž๋งŒ ํ˜ธ์ถœ โ†’ ํŒŒ์ƒ ๋ฆฌ์†Œ์Šค ๋ˆ„์ˆ˜
  • virtual์ด๋ฉด โ†’ vtable ๋™์  ๋””์ŠคํŒจ์น˜ โ†’ ํŒŒ์ƒ ์†Œ๋ฉธ์ž๋ถ€ํ„ฐ ํ˜ธ์ถœ
1
2
3
4
class Base { public: virtual ~Base(){} };
class Derived : public Base {};
Base* p = new Derived();
delete p;   // virtual ์•„๋‹ˆ๋ฉด Derived ์†Œ๋ฉธ์ž ํ˜ธ์ถœ ์•ˆ ๋จ

POD ํƒ€์ž…

  • Plain Old Data โ€” int, float, char, ๋‹จ์ˆœ ๊ตฌ์กฐ์ฒด
  • ์ƒ์„ฑ์ž/์†Œ๋ฉธ์ž๊ฐ€ ์˜๋ฏธ ์—†๋Š” ํƒ€์ž… โ†’ malloc ์‚ฌ์šฉ ๊ธฐ์ˆ ์ ์œผ๋กœ๋Š” OK
  • C++์—์„œ๋Š” ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด new/delete ๊ถŒ์žฅ

new(nothrow)

  • ์˜ˆ์™ธ ๋Œ€์‹  nullptr ๋ฐ˜ํ™˜
  • ์˜ˆ์™ธ๋ฅผ ์“ฐ๊ธฐ ์‹ซ์„ ๋•Œ (์ž„๋ฒ ๋””๋“œ, ๊ตฌํ˜• ์ฝ”๋“œ)
1
2
int* p = new(nothrow) int[N];
if (!p) { /* ์‹คํŒจ ์ฒ˜๋ฆฌ */ }

๋งˆ๋ฌด๋ฆฌ ํ•œ ์ค„

C++์—์„œ๋Š” ๊ฐ์ฒด์˜ ์ƒ์„ฑยท์†Œ๋ฉธ์„ ํƒ€์ž…์ด ์ฑ…์ž„์ง€๋„๋ก ์„ค๊ณ„๋ผ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๋ณด์žฅํ•˜๋Š” new/delete๊ฐ€ ์›์น™์ด๊ณ , ๋” ์•ˆ์ „ํ•˜๊ฒŒ๋Š” ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ๋ฅผ ์”๋‹ˆ๋‹ค. malloc์€ C ์ธํ„ฐํŽ˜์ด์Šค์™€์˜ ํ˜ธํ™˜์ด๋‚˜ POD์—์„œ๋งŒ ์ œํ•œ์ ์œผ๋กœ ์”๋‹ˆ๋‹ค.

๊ด€๋ จ CS ์ฃผ์ œ

  • operator new ํ•จ์ˆ˜ โ€” new ํ‘œํ˜„์‹์˜ ๋‚ด๋ถ€ ๋™์ž‘
  • virtual ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ฒ˜๋ฆฌ โ€” vtable๊ณผ ๋™์  ๋””์ŠคํŒจ์น˜
  • ์†Œ๋ฉธ์ž๋ฅผ Virtual๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ์ด์œ 
  • class์™€ struct์˜ ์ฐจ์ด์ 
  • ์ธ๋ผ์ธ ํ•จ์ˆ˜ (์ƒ์„ฑ์ž/์†Œ๋ฉธ์ž ํ˜ธ์ถœ ๋น„์šฉ)

๋ณด์ถฉ 1 โ€” ์—ฐ์‚ฐ์ž(operator)๋ž€?

  • ์—ฐ์‚ฐ์ž(operator) = ํ”ผ์—ฐ์‚ฐ์ž์— ์–ด๋–ค ์ •ํ•ด์ง„ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์–ธ์–ด๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ธฐํ˜ธ/ํ‚ค์›Œ๋“œ
  • ์‚ฐ์ˆ (+, -, *, /), ๋น„๊ต(==, <), ๋…ผ๋ฆฌ(&&, ||), ๋Œ€์ž…(=), ํฌ์ธํ„ฐ(*, &), ๋ฉ”๋ชจ๋ฆฌ(new, delete) ๋“ฑ
  • ํ•จ์ˆ˜์ฒ˜๋Ÿผ โ€œ์ž…๋ ฅ์„ ๋ฐ›์•„ ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค์ค€๋‹คโ€ โ†’ C++ ๋‚ด๋ถ€์—์„  ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ํ™˜์‚ฐ๋จ
  • a + b๋Š” ์ปดํŒŒ์ผ๋Ÿฌ ์ž…์žฅ์—์„œ operator+(a, b)์™€ ๋™์ผ

new๊ฐ€ โ€œ์—ฐ์‚ฐ์žโ€์ธ ์ด์œ :

  • new Player() ํ‘œํ˜„์‹์€ ๋‚ด๋ถ€์ ์œผ๋กœ 2๋‹จ๊ณ„ ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ํ’€๋ฆผ
    1. operator new(sizeof(Player)) โ€” ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ํ•จ์ˆ˜ ํ˜ธ์ถœ
    2. Player::Player() โ€” ์ƒ์„ฑ์ž ํ˜ธ์ถœ

๋ณด์ถฉ 2 โ€” operator ํ•จ์ˆ˜๋ž€?

์—ฐ์‚ฐ์ž์˜ ๋™์ž‘์„ ํ•จ์ˆ˜๋กœ ์ •์˜/์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” C++ ๋ฌธ๋ฒ•.

  • ๋ฌธ๋ฒ•: ๋ฐ˜ํ™˜ํƒ€์ž… operator๊ธฐํ˜ธ(๋งค๊ฐœ๋ณ€์ˆ˜) ํ˜•ํƒœ๋กœ ์„ ์–ธ
  • ์—ฐ์‚ฐ์ž ์˜ค๋ฒ„๋กœ๋”ฉ(Operator Overloading)
  • ๋Œ€ํ‘œ ์˜ˆ: operator+, operator==, operator[], operator new / operator delete
1
2
3
4
5
6
7
struct FVector2D {
    float X, Y;
    FVector2D operator+(const FVector2D& Rhs) const {
        return { X + Rhs.X, Y + Rhs.Y };
    }
    float operator[](int i) const { return i == 0 ? X : Y; }
};

๋ณด์ถฉ 3 โ€” virtual๊ณผ override

virtual

  • ํ•จ์ˆ˜ ์•ž์— ๋ถ™์ด๋ฉด ๋™์  ๋””์ŠคํŒจ์น˜(dynamic dispatch) ํ™œ์„ฑํ™”
  • ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํฌ์ธํ„ฐ/๋ ˆํผ๋Ÿฐ์Šค๋กœ ํŒŒ์ƒ ๊ฐ์ฒด๋ฅผ ํ˜ธ์ถœํ•ด๋„, ์‹ค์ œ ํƒ€์ž…์˜ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋จ
  • ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํด๋ž˜์Šค๋งˆ๋‹ค vtable(๊ฐ€์ƒ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ํ…Œ์ด๋ธ”)์„ ๋งŒ๋“ค๊ณ , ๊ฐ์ฒด๋Š” vptr๋กœ ์ด ํ…Œ์ด๋ธ”์„ ๊ฐ€๋ฆฌํ‚ด
  • vptr โ†’ vtable โ†’ ์‹ค์ œ ํ•จ์ˆ˜ ์ˆœ์œผ๋กœ ์ฐพ์•„๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ์•ฝ๊ฐ„์˜ ๊ฐ„์ ‘ ํ˜ธ์ถœ ์˜ค๋ฒ„ํ—ค๋“œ

override

  • C++11์—์„œ ์ถ”๊ฐ€๋œ ํ‚ค์›Œ๋“œ โ€” ํŒŒ์ƒ ํด๋ž˜์Šค์—์„œ ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•œ๋‹ค๋Š” ์˜๋„๋ฅผ ๋ช…์‹œ
  • ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ •๋ง ๊ธฐ๋ฐ˜์˜ virtual ํ•จ์ˆ˜๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์˜ค๋ฒ„๋ผ์ด๋“œํ–ˆ๋Š”์ง€ ๊ฒ€์‚ฌ
  • ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์‹ค์ˆ˜๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œ๊ฐ€ ๊นจ์ง€๋Š” ๋ฒ„๊ทธ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์ฐจ๋‹จ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Monster {
public:
    virtual void Attack() { cout << "๊ธฐ๋ณธ ๊ณต๊ฒฉ\n"; }
    virtual ~Monster() {}   // โ† ๊ธฐ๋ฐ˜ ์†Œ๋ฉธ์ž virtual ํ•„์ˆ˜
};

class Boss : public Monster {
public:
    void Attack() override { cout << "๋ณด์Šค ๊ณต๊ฒฉ!\n"; }
    // override ๋•๋ถ„์— ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์‹ค์ˆ˜ ์‹œ ์ปดํŒŒ์ผ ์—๋Ÿฌ
};

Monster* m = new Boss();
m->Attack();   // "๋ณด์Šค ๊ณต๊ฒฉ!"
delete m;      // Boss โ†’ Monster ์†Œ๋ฉธ์ž ์—ฐ์‡„

์ •๋ฆฌ:

  • virtual = โ€œ์ด ํ•จ์ˆ˜๋Š” ์ž์‹์ด ๊ฐˆ์•„๋ผ์šธ ์ˆ˜ ์žˆ๋‹คโ€๋ผ๊ณ  ๋ถ€๋ชจ๊ฐ€ ํ—ˆ๋ฝ
  • override = โ€œ๋‚ด๊ฐ€ ๋ถ€๋ชจ ํ•จ์ˆ˜๋ฅผ ๊ฐˆ์•„๋ผ์šด๋‹คโ€๋ผ๊ณ  ์ž์‹์ด ์•ฝ์†
์ด ๊ธฐ์‚ฌ๋Š” ์ €์ž‘๊ถŒ์ž์˜ CC BY 4.0 ๋ผ์ด์„ผ์Šค๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

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

Powered by Jekyll with Chirpy theme

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