글 작성자: Sowhat_93

기본적으로 사용하는 new를 사용해보자.

#include <iostream>

class MyClass
{
private:
	int Number = 9935;

public: 
	MyClass() 
	{
		std::cout << "MyClass!" << std::endl;
	}
	virtual ~MyClass() {}
};

int main()
{
	MyClass* pMyInstance = new MyClass();
}

결과는 아주 쉽다.

당연히 생성자 함수가 호출된다.

위의 MyClass* pMyInstance = new MyClass();

 

에서 호출되는 new는 void* operator new (size_t Size)이다.

왜 Size를 인자로 원할까.

 

저 Size를 받으면,

다음과 같이 동작한다.

void* pMemForInstance = malloc(Size);

return pMemForInstance; 

 

malloc이랑 별 차이가 없다.

???

MyClass* pMyInstance = new MyClass() 에서

Size를 인자로 전달한적 없다.

C++ 컴파일러가 new를 어셈블리어로 바꿀때

알아서 집어넣는 추가적인 작업이 있다는 이야기이다.

그 추가적인 작업에 생성자 호출과 객체의 메모리 블럭 초기화가 포함된다. 

 

 

모든 new 연산자 호출시 생성자 호출과 객체의 메모리 블럭 초기화가 자동으로 따라 붙는다.

이것은 C++ 컴파일러의 컴파일방식을 바꾸지 않는다면 무조건 들어간다.

 

 

그럼 다시 돌아가보자.

void* operator new (size_t Size)는

1. Size만큼 동적할당한다. (C++ 코드로 정의됨.)

2. C++ 컴파일러가 알아서 생성자 호출과 객체의 메모리블럭 초기화.

 

따라서.

void* operator new (size_t Size)를 동적할당을 하지 않도록

오버로딩을 통해 재정의를 한다.

그러면 생성자의 호출만 쏙 골라 빼먹을 수 있다.

 

이 형태가 미리 정의 된 형태가 바로

void* opreator new(size_t Size, void* pAddress) 형태이다.

물론 이것도 오버로딩 가능하다.

디폴트 구현은 어떻게 되어있느냐.

void* opreator new(size_t Size, void* pAddress)
{
	(void)Size;
	return pAddress;
}

정말로 아무것도 안한다.

컴파일러에게 생성자 호출 코드를 집어넣도록 시키기 위해 만들어 둔 것이다.

호출은 다음과 같이 한다.

MyClass* pMyInstance = (MyClass*)malloc(sizeof(MyClass));
new (pMyInstance) MyClass;

 

실행해보면,

생성자 정상적으로 호출되며, 메모리블럭은 정의된 클래스형식에 맞게 깔끔하게 초기화 되어있다.

 

 

 

생성자만 여러번 호출해보자.

MyClass* pMyInstance = (MyClass*)malloc(sizeof(MyClass));

new (pMyInstance) MyClass;
new (pMyInstance) MyClass;
new (pMyInstance) MyClass;
new (pMyInstance) MyClass;
new (pMyInstance) MyClass;
new (pMyInstance) MyClass;