Minwoo Dev.
[C++] operator new, operator new[] 본문
이번에는 new 연산자를 오버로딩 해보겠다.
우선, new 연산자의 역할을 먼저 알아보자면 아래와 같다.
- 메모리 공간의 할당
- 생성자의 호출
- 할당하고자 하는 자료형에 맞게 반환된 주소 값의 형 변환
위 세 가지 역할 중에서 우리는 메모리 공간의 할당에 해당되는 부분만 오버로딩을 할 수 있다.
다른 두 가지는 컴파일러의 역할이기 때문이다.
메모리 공간의 할당에 대한 순서를 알아보면,
- 필요한 메모리 공간을 계산
- 계산된 크기의 값을 인자로 전달하여 operator new 호출
operator new
우선 new 연산자 오버로딩에서는 필수적으로 지켜저야 할 것이 있다.
- 매개변수로 들어가는 인자는 size_t 이어야 한다.
- 반환형은 void * 이어야한다.
- 인자로 전달하는 size는 바이트 단위로 전달되어야 한다.
위 조건을 지켜서 new 연산자의 틀을 작성해보면,
void * operator new(size_t size){
void* adr = new char[size];
return adr;
}
위와 같은 형식이 기본이 된다.
왜 new char[size]에서 char으로 동적 할당을 수행하냐고 궁금증이 생길 수 있다.
C++에서 char 자료형의 메모리 크기가 얼마인지 아는가 ?
바로 1바이트 이다.
위 조건에서 인자로 전달하는 size는 바이트 단위로 전달되어야 한다고 하였기에, 1바이트를 사용하는 char을 이용해 동적 할당을 수행한 것이다.
이제 실제 클래스 내부에 포함시킨 예제 코드를 살펴보겠다.
#include<iostream>
using namespace std;
class Point{
private:
int xpos, ypos;
public:
Point(int x=0,int y=0):xpos(x),ypos(y){}
friend ostream &operator<<(ostream &os, const Point &pos);
void * operator new (size_t size){ // new 연산자 오버로딩
cout << "operator new : " << size << endl;
void *adr = new char[size];
return adr;
}
void operator delete(void * adr){
cout << "operator delete ()" << endl;
delete[] adr;
}
};
ostream& operator<<(ostream& os, const Point& pos){
os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
return os;
}
int main(void){
Point *ptr = new Point(3, 4);
cout << *ptr;
delete ptr;
return 0;
}
실행 결과
위 코드에서의 new 연산자 오버로딩은 operator new의 사이즈를 출력하는 코드를 추가하는 방식으로 오버로딩을 진행하였다.
참고로, size_t size에는 계산된 바이트의 크기가 들어가게 된다.
int형 변수 두 개가 있으므로 게산된 바이트의 크기는 4*2 = 8인 것이다.
이렇듯 new 연산자의 오버로딩은 기존에 있던 틀을 유지하되, 다른 것들을 추가할 수 있다는 방식이다.
operator new[]
컴파일러가 바이트를 계산하여 매개변수로 넘겨주기 때문에, new[] 연산자는 new 연산자의 오버로딩과 내용이 같다.
void * operator new[](size_t size){
void* adr = new char[size];
return adr;
}
컴파일러가 size를 계산하여 넣어주기 때문에 함수의 내용은 바꾸지 않아도 된다.
예제 코드를 보자.
#include<iostream>
using namespace std;
class Point{
private:
int xpos, ypos;
public:
Point(int x=0, int y=0):xpos(x),ypos(y){}
friend ostream &operator<<(ostream &os, const Point &pos);
void * operator new (size_t size){ // 기존의 new 연산자 오버로딩
cout << "operator new : " << size << endl;
void *adr = new char[size];
return adr;
}
void * operator new[] (size_t size){ // new[] 연산자 오버로딩
cout << "operator new [] : " << size << endl;
void *adr = new char[size];
return adr;
}
void operator delete(void * adr){
cout << "operator delete() " << endl;
delete[] adr;
}
void operator delete[](void * adr){
cout << "operator delete[] () " << endl;
delete[] adr;
}
};
ostream& operator<<(ostream& os, const Point& pos){
os << '[' << pos.xpos << ", " <<pos.ypos<< ']' << endl;
return os;
}
int main(void){
Point *ptr = new Point(3, 4);
Point *arr = new Point[3];
delete ptr;
delete[] arr;
return 0;
}
실행 결과
size를 컴파일러가 계산하여 매개변수로 전달하기 때문에 new 연산자 오버로딩 함수와 new [] 연산자 오버로딩 함수의 내용이 똑같음에도 도 size가 다르게 입력되어 원하는 대로 결과가 출력되는 것을 확인할 수 있다.
정리하자면, new 연산자는 메모리 공간의 할당만 오버로딩으로 사용할 수 있으며, 정해진 형식(void* 반환, 매개변수 size_t)를 지켜서 작성해야하고, 컴파일러가 크기를 계산하여 size에 매개변수로 넣어준다는 점이다.
'C++' 카테고리의 다른 글
[C++] 윤성우의 열혈 C++ 13-1 함수 템플릿의 정의 문제풀이 (0) | 2024.07.23 |
---|---|
[C++] 포인터 연산자 오버로딩, operator*, operator-> (2) | 2024.07.23 |
[C++] 배열의 인덱스 연산자 오버로딩, operator[] (0) | 2024.07.23 |
[C++] 윤성우의 열혈 C++ 11-2 C++ 기반의 데이터 입출력 문제풀이 (0) | 2024.07.21 |
[C++] 윤성우의 열혈 C++ 11-1 깊은 복사를 하는 대입 연산자의 정의 문제풀이 (0) | 2024.07.21 |