๐ 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๊ฐ์ง
| # | ํญ๋ชฉ | new | malloc |
|---|
| 1 | ๋ถ๋ฅ | C++ ์ฐ์ฐ์ (operator) | C ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํจ์ |
| 2 | ์์ฑ์/์๋ฉธ์ | ํธ์ถ O | ํธ์ถ X (raw ๋ฉ๋ชจ๋ฆฌ) |
| 3 | ์คํจ ์ฒ๋ฆฌ | std::bad_alloc throw | NULL ๋ฐํ |
| 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_ptr | shared_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๋จ๊ณ ํจ์ ํธ์ถ๋ก ํ๋ฆผoperator new(sizeof(Player)) โ ๋ฉ๋ชจ๋ฆฌ ํ ๋น ํจ์ ํธ์ถ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 = โ๋ด๊ฐ ๋ถ๋ชจ ํจ์๋ฅผ ๊ฐ์๋ผ์ด๋คโ๋ผ๊ณ ์์์ด ์ฝ์