new와 malloc의 차이점 포스트가 아니니 아래의 내용은 안읽고 바로 operator new에 대해서 읽어도 무방하다.
operator new와 malloc의 차이점은 아래와 같다.
1. new는 생성자를 호출하지만
- malloc은 생성자를 호출하지 않는다.
2. new는 호출한 클래스 타입의 포인터를 반환하지만
- malloc은 void*로 반환한다.
3. new로 동적할당을 하면 delete로 해제해 주어야 하지만
- malloc은 free로 해제 해야한다.
4. 추가로 delete는 소멸자를 호출하고
- free는 호출하지 않는다.
자, 그럼 이제 왜 operator new를 설명하는데 위 개념이 필요한지 알아보자.
operator new
new가 하는일은 위에서도 설명했듯이
1. 메모리를 할당하고
2. 생성자를 호출하여 초기화 해준다.
위 두 가지 일은 사용자가 아무리 바꾸려해도 바뀌지 않는 불변의 법칙이다.
사용자가 바꿀 수 있는 것이라고는 new에서 수행하는 첫번째 일인 '메모리를 할당하는 방법'이다. (두번째는 이후에 설명하겠다.)
다시말해 new함수에서 메모리를 할당하기위해 malloc과 같은 기능의 어떤 함수를 호출하는데
그 어떤 함수를 오버로딩하여 변화를 줄수 있다는 의미이다.
그 함수의 이름이 operator new인 것이다.
operator new를 오버로딩하게 되면 new에서 호출하는 operator new가 바로 내가 오버로딩한 함수가 되는 것이다.
얼마나 할일이 없으면 저런것까지 오버로딩을 하지? 라는 생각을 하고 있다면 큰 오산이다.
위에서 말했듯이 메모리를 할당하는 방법을 오버로딩한다는 것은 다음과 같은 것을 할 수 있다는 이야기이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | CObject* CObject::create() { // 여기서 operator new가 호출됨 CObject* pRet = (CObject*)new(std::nothrow)CObject(); if (pRet && pRet->init()) { return pRet; } else { delete pRet; pRet = NULL; return NULL; } } void* CObject::operator new(size_t size, const std::nothrow_t) { // PoolingManager에서 메모리를 할당 받는다. return CPoolingManager::Instance()->ObjectNew(); } | cs |
어떤 Object클래스의 한 부분이다.
이 클래스는 생성자와 소멸자를 private으로 은닉화 시켜놓고 create으로만 객체를 생성할 수 있다.
(이렇게 하면 생성시 꼭 해야할 일들을 수행할 수 있다. )
create함수를 보면 new를 하고 있는데 이때 new안에서 호출되는 operator new함수는 내가 오버로딩한 것이다.
때문에 실제 메모리는 할당되지 않으며 내가 오버로딩한 함수를 호출하는데,
내가 오버로딩해 놓은 함수를 보니 어딘가에서 메모리를 얻어오는 것을 알 수 있다.(이부분에 대해서는 [MemoryPooling_2] 포스트를 참고하자)
위와 같은 방식으로 메모리를 조금더 효율적으로 할당할 수 있게 된다.(마찬가지로 무엇이 효율적인지에 대해서는 [MemoryPooling_1] 포스트를 참고하자)
operator delete
기본적인 원리는 앞에서 설명한 것과 같다. 단지 메모리를 해제하는 방식을 operator delete로 오버로딩하여 변경할 수 있다는 것이 다를 뿐이다.
1 2 3 4 5 | void* CObject::operator delete(void* p) { // PoolingManager에서 메모리를 메모리 블럭으로 되돌린다. return CPoolingManager::Instance()->ObjectDelete(p); } | cs |
PoolingManager의 ObjectDelete를 호출하는데 이 함수안에서는 메모리를 해제하는 것이 아니라 Free상태로 놓는다.
(Free상태의 메모리는 다시 create함수를 이용하여 사용상태로 전환될 수 있는 휴면상태 메모리이다.)
생성자 호출
위와 같은 방식으로 메모리를 초기화 하면 말 그대로 순수 메모리를 얻게될 것이다.
마치 malloc으로 얻은 메모리처럼 말이다.
위에서는 마치 일반적인 operator new가 메모리도 할당하고 생성자도 알아서(?) 호출해주는 것처럼 말했지만
사실 메모리 할당과 생성자 호출은 별개의 문제이다.
일반적으로 operator new를 호출 한다고 해서 생성자까지 호출해주지는 않는다.
위의 방식처럼 사용하기 위해서는 생성자가 호출되어야 하는데 말이다. (메모리 블럭을 객체로사용하는 방식)
이것을 가능하게 해주는 것이 바로 위치지정(placement) operator new라는 것이다.
쉽게 operator new의 확장판이라 인자로 전달되는 포인터 타입의 생성자를 호출해준다고 이해하면되겠다.
이렇게 생성자 호출이 끝나야만 해당 메모리는 제대로 객체로써 이용할 수 있게된다.
'All > C++' 카테고리의 다른 글
자주 사용하는 STL function (0) | 2016.11.28 |
---|---|
메모리 누수 검사 (0) | 2015.12.29 |
가변인자 로그 출력함수 (0) | 2015.12.29 |
RValue와 LValue (2) | 2015.12.28 |
문장줄이기 (0) | 2015.12.28 |