Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo

1

EFFECTIVE C++ 정리
Chapter 8
new / delete

2

new 처리자
ITEM 49

3

Item 49: new 처리자
• new 처리자
• 메모리 할당이 제대로 이루어지지 않은 경우 예외처리!
• 예외처리에 앞서 사용자의 커스텀 예외처리자, new-handler가 호출됨
• set_new_handler를 통해서 설정가능.
namespace std {
typedef void (*new_handler) ();
new_handler set_new_handler(new_handler p) throw ();
}

4

Item 49: new 처리자
• new 처리자에서 해줄 수 있는 일들
• 메모리 추가 확보
• 다른 new 처리자를 찾아서 호출
• NULL – 즉 default 예외처리
• 커스텀 예외처리 ( bad_alloc )

5

Item 49: new 처리자
• 클래스 별로 별도의 new handler를 사용하고 싶다면
• c++ 자체기능은 없으니 직접 만들어야함.
• 클래스 커스텀 set_new_handler
• new 처리자(함수)를 받아오는 역할
• operator new 오버라이딩
• 메모리 할당이 실패한 경우 클래스 자체 new-handler를 호출

6

Item 49: new 처리자
• set_new_handler
• new_handler Widget::set_new_handler(new_handler p) throw()
{
new_handler oldHandler = currentHandler;
currentHanlder = p;
return oldHandler;
}

7

Item 49: new 처리자
• operator new
• 표준 set_new_handler 함수에 Widget의 new_handler를 넘겨준다.
• new_handler 변경한 채로 new 호출, 종료 후 new_handler 복원
• 실패 시 bad_alloc 쓰로우 & new_handler 복원
• 위 작업에서 new_handler 복원 처리를 별도의 자원관리자를 통해서 만
들면 쉽게 구현가능
• new_handler 관리자 NewHandlerHolder를 만들자.

8

Item 49: new 처리자
• class NewHandlerHolder{
public:
explicit NewHandlerHolder(new_handler nh)
: handler (nh) { } //생성자에서 new_handler 받기
~NewHandlerHolder() //소멸자에서 set_new_handler호출
{ set_new_handler(handler); }
private:
new_handler handler;
}

9

Item 49: new 처리자
• Widget의 operator new
void* Widget::operator new(size_t size) throw(bad_alloc)
{
NewHandlerHolder h(set_new_handler(currentHolder));
// 기존의 newHandler를 저장한다.
return ::operator new(size); // 할당 작업 진행
//실패해도 NewHandlerHolder의 소멸자 호출  handler 복원
}

10

Item 49: new 처리자
• 템플릿화 해서 상속받아 사용할 수 있게 하자.
template<typename T>
class NewHandlerSupport {
public :
static new_handler set_new_handler( new_handler p );
static void* operator new(size_t size) throw(bad_alloc);
}

11

Item 49: new 처리자
• 상속 받아서 사용하는 방법
• class Widget : public NewHandlerSupport<Widget>
• template에서 T가 한번도 안쓰이는 데?
• 클래스별로 별도의 NewHandlerSupport가 필요함
• 클래스마다 각각 currentHandler가 다를 것이므로.
• T를 받아서 별도의 NewHandlerSupport를 만들어주기 위함
• CRTP라고 하는 자주 사용되는 패턴

12

Item 49: new 처리자
• 예외 불가 new ( 추가 이슈 )
• 예전에 할당실패 시 bad_alloc Throw말고 그냥 NULL을 리턴했다.
• 지금도 예외불가 new 하는 방법은 존재
new (std::nothrow) Widget ;
• 하지만 예외불가는 오직 Widget 공간 할당에 한해서만 적용된다.
• 내부 생성자에서 다시 new를 해서 실패한 예외는 적용 안됨
• 어쨌든 new_handler의 동작 구조를 잘 알아두자.

13

적절한 operator
new/delete
ITEM 50

14

Item 50: 적절한 operator new/delete
• 왜 new와 delete를 오버라이딩 하는가
• 잘못된 힙 사용 방지
• delete 두 번
• 할당 영역을 넘어선 접근 ( 오버런, 언더런 )
• 통계 수집
• 할당된 메모리 블록의 크기 / 사용기간 분포
• 메모리 사용패턴

15

Item 50: 적절한 operator new/delete
• 왜 new와 delete를 오버라이딩 하는가
• 할당 / 해제 성능 효율
• 특정한 조건에 할당/해제 작업에 최적화 할 수 있다.
• 고정크기의 객체만 만드는 경우
• 싱글 쓰레드 환경이 보장된 경우
• 공간 오버헤드를 최소화
• 안정적인 사용을 위해 다소 불필요한 메모리 공간(관리 영역) 발생
• 별도로 관리자가 따로 있다면 관리영역을 많이 줄일 수 있다.

16

Item 50: 적절한 operator new/delete
• 왜 new와 delete를 오버라이딩 하는가
• 바이트 정렬 보장
• 시스템 아키텍처를 최대한 활용하기 위해 메모리를 8바이트 단위 정렬할 수 있다.
• 기존 컴파일러가 이를 보장하지 않는 경우가 종종 있기 때문에 별도로 제작
• 같은 자료구조, 관계 있는 객체들의 물리적 locality 증대
• 객체를 별도로 할당을 관리하여 메모리의 locality를 증대시킬 수 있다.
• new / delete 시 별도의 동작 추가

17

Item 50: 적절한 operator new/delete
• 오버런 / 언더런 처리 operator new
void* operator new (size_t size) throw (bad_alloc)
{
size_t realSize = size + 2 * sizeof(int); //경계 표시영역 2개
void* pMem = malloc(realSize);
if(!pMem) throw bad_alloc();
*(static_cast<int*>(pMem)) = 0xDEADBEEF; //경계표시 1 (언더런 방지)
*(reinterpret_cast<int*>(static_cast<BYTE*> //경계표시 2 (오버런 방지)
(pMem) + realSize – sizeof(int))) = 0xDEADBEEF;
return static_cast<BYTE*>(pMem) + sizeof(int); //실제 메모리 시작위치 반환
}

18

Item 50: 적절한 operator new/delete
• 위 operator new의 문제점
• new_handler 호출 루프가 없음 (item 51에서 자세히)
• 바이트 정렬
• malloc해서 받은 값에서 int만큼 offset 이동시킨 주소를 리턴 하고 있음
• 메모리가 제대로 정렬된 상태가 아닐 가능성!
• 2^n 크기로 데이터들을 정렬해야 최적화된다.
• 아키텍처에 따라서 잘못된 동작을 야기할 수 도 있다.
• 멀티 쓰레드에 대한 개념 전혀 없음

19

Item 50: 적절한 operator new/delete
• 가능하면 전문가에게 맡기자
• 메모리 관리자를 잘 만들기란 쉽지 않은 일이다.
• 일반적인 경우 컴파일러의 기본 operator new/delete는 훌륭하다.
• 특별한 경우 라이브러리의 도움을 받자.
• boost::Pool : 크기가 작은 객체를 많이 할당/해제하는 경우
• 정렬 이슈/ 멀티 쓰레드 이슈가 잘 정리되어 있다.
• 직접 만들기 전에 라이브러리 코드를 보고 배우는 것도 도움이 될 것이다.

20

operator new/delete의
convention
ITEM 51

21

Item 51: operator new/delete의 convention
• operator new에서 convention
• 확실한 반환 값
• 요청된 메모리의 포인터를 반환
• 0 size 메모리 요청 대비
• 할당 실패시 우선 new 처리자 함수를 호출
• 그래도 안되면 bad_alloc throw
• 기존 new를 완전히 덮어 쓰지 말것 (item 52에서 자세히)

22

Item 51: operator new/delete의 convention
• 실제로 구현 하기
void* operator new (size_t size) throw (bad_alloc)
{
if( size == 0 ) size = 1; //0바이트 요청은 1바이트로 바꿔서
while( true ) { //할당이 되던가, bad_alloc이 뜨던가 둘중하나가 될때까지 반복
void* pMem = malloc( size );
if( pMem != NULL) return static_cast<T>(pMem);
//할당 실패시 현재 new_handler찾아서 실행
new_handler globalHandler = set_new_handler( NULL );
set_new_handler(globalHandler);
if( globalHandler ) (*globalHandler)( );
else throw bad_alloc( ); //new_handler 없으면 bad_alloc 처리
}
}

23

Item 51: operator new/delete의 convention
• 클래스 멤버변수 operator new의 convention
• operator new 또한 상속된다.
• 상속받은 클래스가 Base의 operator new를 호출했을 경우를 체크하자.
• item 50의 경우처럼 특수한 new를 만들었을 경우 기본 new를 호출할 수 있게
void* Base::operator new (size_t size) throw (bad_alloc) {
if( size != sizeof(Base) ) //틀린 크기가 들어오면 기존의 ::operator new사용
return ::operator new( size );
…
}
• 클래스의 크기는 최소 1이므로 0바이트 체크까지 되는 코드임

24

Item 51: operator new/delete의 convention
• operator new[] 에서 convention
• 단순히 주어진 사이즈의 메모리 덩어리를 할당하면 된다.
• 배열 정보를 함부로 추론하려 하지마라
• 몇 개의 객체가 들어올지 예측할 수 없다.
• new를 호출할 파생 클래스 객체의 사이즈를 알 수 없다.
• 안다고 해도 new [] 는 실제 객체 * 배열 길이 보다 더 큰 사이즈를 할당한다.
• item 16에서 언급한 헤더정보가 추가된다.

25

Item 51: operator new/delete의 convention
• operator delete에서 convention
• null포인터 exception만 조심하면 된다.
void operator delete( void* rawMemory ) throw ()
{
if ( rawMemory == NULL ) return; //NULL delete 방지
//메모리 해제 작업
…
}

26

Item 51: operator new/delete의 convention
• 클래스 멤버변수 operator delete 에서 convention
• 상속받은 클래스가 BASE의 operator delete를 호출하는 경우를 체크하자.
void Base::operator delete ( void* rawMemory, size_t size ) throw ()
{
if ( rawMemory == 0 ) return; //NULL 체크
if ( size != sizeof( Base ) ) {
::operator delete( rawMemory );
return;
}
//메모리 해제 작업
…
}

27

위치지정 new / delete
ITEM 52

28

Item 52: 위치지정 new / delete
• new 호출의 문제점
• Widget* pw = new Widget();
1. 메모리 할당을 위해 operater new 호출
2. Widget의 기본생성자 호출
• 메모리 할당은 잘 되었는데 Widget 생성자에서 exception?
• 런타임 시스템에서 operator new와 짝이 되는 operator delete를 호출해준다.
• 기본형의 경우는 문제없이 Pair로 잘 구성되어 있다.
• void operator new(size_t) throw (bad_alloc);
• void operator delete(void* rawMemory) throw( );
• 기본형이 아닌 operator new가 문제의 시작 (무엇이 Pair인가?)

29

Item 52: 위치지정 new / delete
• 기본형이 아닌 operator new (placement new)
• 할당시 log를 찍는 operator new 와 그 짝 delete
• void* operator new ( size_t size, ostream& logStream ) throw ( bad_alloc )
• void operator delete ( void* pMemory, size_t size) throw ( );
• 매개변수를 따로 받는 operator new 를 위치지정 new라고 한다.
• 자주 사용되던 미리 할당할 메모리 위치를 매개변수로 받는 new에서 시작
void operator new ( size_t size, void* pMemory) throw ( );
• ex : vector의 미사용 공간에 원소 객체를 할당-생성 할 때

30

Item 52: 위치지정 new / delete
• 런타임 시스템에서 Pair가 되는 operator delete를 찾는 법
• 추가 매개변수의 개수 및 타입이 똑같은 operator delete를 Pair로
• 위 로그 찍는 operator new/delete 예제에서는 서로 짝이 안 맞는다.
• 새로운 operator delete 선언
void operator delete( void* pMemory, ostream& logStream ) throw ();
• 이런 operator delete를 위치지정 delete라고 부른다.

31

Item 52: 위치지정 new / delete
• 만약 예외처리 없이 일반적으로 delete를 호출한다면?
• 런타임 시스템은 기본형의 operator delete를 호출한다.
• 위치지정 delete는 위치지정 new의 Pair가 필요할 때만 호출된다.
• 따라서 표준형태의 operator delete는 기본으로 항상 마련해야 한다.
• 추가적으로 위치지정 new를 썼다면 위치지정 delete도 만들어야 한다.

32

Item 52: 위치지정 new / delete
• operator new의 오버라이딩 문제 (이름 가림 이슈)
• 이름 문제의 디테일은 item 33 참조
• 전용의 operator new가 다른 operator new들을 가리지 않도록!
• Widget 클래스에서 위치지정 new만 선언/정의했다면?
Widget* pw = new Widget(); //error! 전역 operator new를 가린다.
• 전역에서 유효한 operator new 형태들
• void* operator new(std::size_t) throw (std::bad_alloc); //기본형 new
• void* operator new(std::size_t, void*) throw (); // 위치지정 new
• void* operator new(std::size_t, const std::nothrow_t&) throw(); //예외 불가 new

33

Item 52: 위치지정 new / delete
• 클래스에서 operator new를 정의하려면
• 모든 형태의 operator new및 pair가 되는 operator delete 정의필요
• 미리 operator들을 부를 수 있는 인터페이스 클래스를 만들어두자.
class StandardNewDeleteForms { //모든 종류의 operator new들을 선언한 인터페이스
public:
static void* operator new(std::size_t size) throw(std::bad_alloc)
{ return ::operator new(size); }
…
}

34

Item 52: 위치지정 new / delete
• 실제 사용 예
class Widget : public StandardNewDeleteForms { //인터페이스 상속
public:
using StandardNewDeleteForms::operator new; //이름영역 공유
using StandardNewDeleteForms::operator delete;
//별도의 위치지정 operator new /delete
static void* operator new(size_t size, void* pAlloc) throw (bad_alloc);
static void operator delete(void* pMemory, void* pAlloc) throw ();
}

More Related Content

Effective c++ 정리 chapter 8

  • 3. Item 49: new 처리자 • new 처리자 • 메모리 할당이 제대로 이루어지지 않은 경우 예외처리! • 예외처리에 앞서 사용자의 커스텀 예외처리자, new-handler가 호출됨 • set_new_handler를 통해서 설정가능. namespace std { typedef void (*new_handler) (); new_handler set_new_handler(new_handler p) throw (); }
  • 4. Item 49: new 처리자 • new 처리자에서 해줄 수 있는 일들 • 메모리 추가 확보 • 다른 new 처리자를 찾아서 호출 • NULL – 즉 default 예외처리 • 커스텀 예외처리 ( bad_alloc )
  • 5. Item 49: new 처리자 • 클래스 별로 별도의 new handler를 사용하고 싶다면 • c++ 자체기능은 없으니 직접 만들어야함. • 클래스 커스텀 set_new_handler • new 처리자(함수)를 받아오는 역할 • operator new 오버라이딩 • 메모리 할당이 실패한 경우 클래스 자체 new-handler를 호출
  • 6. Item 49: new 처리자 • set_new_handler • new_handler Widget::set_new_handler(new_handler p) throw() { new_handler oldHandler = currentHandler; currentHanlder = p; return oldHandler; }
  • 7. Item 49: new 처리자 • operator new • 표준 set_new_handler 함수에 Widget의 new_handler를 넘겨준다. • new_handler 변경한 채로 new 호출, 종료 후 new_handler 복원 • 실패 시 bad_alloc 쓰로우 & new_handler 복원 • 위 작업에서 new_handler 복원 처리를 별도의 자원관리자를 통해서 만 들면 쉽게 구현가능 • new_handler 관리자 NewHandlerHolder를 만들자.
  • 8. Item 49: new 처리자 • class NewHandlerHolder{ public: explicit NewHandlerHolder(new_handler nh) : handler (nh) { } //생성자에서 new_handler 받기 ~NewHandlerHolder() //소멸자에서 set_new_handler호출 { set_new_handler(handler); } private: new_handler handler; }
  • 9. Item 49: new 처리자 • Widget의 operator new void* Widget::operator new(size_t size) throw(bad_alloc) { NewHandlerHolder h(set_new_handler(currentHolder)); // 기존의 newHandler를 저장한다. return ::operator new(size); // 할당 작업 진행 //실패해도 NewHandlerHolder의 소멸자 호출  handler 복원 }
  • 10. Item 49: new 처리자 • 템플릿화 해서 상속받아 사용할 수 있게 하자. template<typename T> class NewHandlerSupport { public : static new_handler set_new_handler( new_handler p ); static void* operator new(size_t size) throw(bad_alloc); }
  • 11. Item 49: new 처리자 • 상속 받아서 사용하는 방법 • class Widget : public NewHandlerSupport<Widget> • template에서 T가 한번도 안쓰이는 데? • 클래스별로 별도의 NewHandlerSupport가 필요함 • 클래스마다 각각 currentHandler가 다를 것이므로. • T를 받아서 별도의 NewHandlerSupport를 만들어주기 위함 • CRTP라고 하는 자주 사용되는 패턴
  • 12. Item 49: new 처리자 • 예외 불가 new ( 추가 이슈 ) • 예전에 할당실패 시 bad_alloc Throw말고 그냥 NULL을 리턴했다. • 지금도 예외불가 new 하는 방법은 존재 new (std::nothrow) Widget ; • 하지만 예외불가는 오직 Widget 공간 할당에 한해서만 적용된다. • 내부 생성자에서 다시 new를 해서 실패한 예외는 적용 안됨 • 어쨌든 new_handler의 동작 구조를 잘 알아두자.
  • 14. Item 50: 적절한 operator new/delete • 왜 new와 delete를 오버라이딩 하는가 • 잘못된 힙 사용 방지 • delete 두 번 • 할당 영역을 넘어선 접근 ( 오버런, 언더런 ) • 통계 수집 • 할당된 메모리 블록의 크기 / 사용기간 분포 • 메모리 사용패턴
  • 15. Item 50: 적절한 operator new/delete • 왜 new와 delete를 오버라이딩 하는가 • 할당 / 해제 성능 효율 • 특정한 조건에 할당/해제 작업에 최적화 할 수 있다. • 고정크기의 객체만 만드는 경우 • 싱글 쓰레드 환경이 보장된 경우 • 공간 오버헤드를 최소화 • 안정적인 사용을 위해 다소 불필요한 메모리 공간(관리 영역) 발생 • 별도로 관리자가 따로 있다면 관리영역을 많이 줄일 수 있다.
  • 16. Item 50: 적절한 operator new/delete • 왜 new와 delete를 오버라이딩 하는가 • 바이트 정렬 보장 • 시스템 아키텍처를 최대한 활용하기 위해 메모리를 8바이트 단위 정렬할 수 있다. • 기존 컴파일러가 이를 보장하지 않는 경우가 종종 있기 때문에 별도로 제작 • 같은 자료구조, 관계 있는 객체들의 물리적 locality 증대 • 객체를 별도로 할당을 관리하여 메모리의 locality를 증대시킬 수 있다. • new / delete 시 별도의 동작 추가
  • 17. Item 50: 적절한 operator new/delete • 오버런 / 언더런 처리 operator new void* operator new (size_t size) throw (bad_alloc) { size_t realSize = size + 2 * sizeof(int); //경계 표시영역 2개 void* pMem = malloc(realSize); if(!pMem) throw bad_alloc(); *(static_cast<int*>(pMem)) = 0xDEADBEEF; //경계표시 1 (언더런 방지) *(reinterpret_cast<int*>(static_cast<BYTE*> //경계표시 2 (오버런 방지) (pMem) + realSize – sizeof(int))) = 0xDEADBEEF; return static_cast<BYTE*>(pMem) + sizeof(int); //실제 메모리 시작위치 반환 }
  • 18. Item 50: 적절한 operator new/delete • 위 operator new의 문제점 • new_handler 호출 루프가 없음 (item 51에서 자세히) • 바이트 정렬 • malloc해서 받은 값에서 int만큼 offset 이동시킨 주소를 리턴 하고 있음 • 메모리가 제대로 정렬된 상태가 아닐 가능성! • 2^n 크기로 데이터들을 정렬해야 최적화된다. • 아키텍처에 따라서 잘못된 동작을 야기할 수 도 있다. • 멀티 쓰레드에 대한 개념 전혀 없음
  • 19. Item 50: 적절한 operator new/delete • 가능하면 전문가에게 맡기자 • 메모리 관리자를 잘 만들기란 쉽지 않은 일이다. • 일반적인 경우 컴파일러의 기본 operator new/delete는 훌륭하다. • 특별한 경우 라이브러리의 도움을 받자. • boost::Pool : 크기가 작은 객체를 많이 할당/해제하는 경우 • 정렬 이슈/ 멀티 쓰레드 이슈가 잘 정리되어 있다. • 직접 만들기 전에 라이브러리 코드를 보고 배우는 것도 도움이 될 것이다.
  • 21. Item 51: operator new/delete의 convention • operator new에서 convention • 확실한 반환 값 • 요청된 메모리의 포인터를 반환 • 0 size 메모리 요청 대비 • 할당 실패시 우선 new 처리자 함수를 호출 • 그래도 안되면 bad_alloc throw • 기존 new를 완전히 덮어 쓰지 말것 (item 52에서 자세히)
  • 22. Item 51: operator new/delete의 convention • 실제로 구현 하기 void* operator new (size_t size) throw (bad_alloc) { if( size == 0 ) size = 1; //0바이트 요청은 1바이트로 바꿔서 while( true ) { //할당이 되던가, bad_alloc이 뜨던가 둘중하나가 될때까지 반복 void* pMem = malloc( size ); if( pMem != NULL) return static_cast<T>(pMem); //할당 실패시 현재 new_handler찾아서 실행 new_handler globalHandler = set_new_handler( NULL ); set_new_handler(globalHandler); if( globalHandler ) (*globalHandler)( ); else throw bad_alloc( ); //new_handler 없으면 bad_alloc 처리 } }
  • 23. Item 51: operator new/delete의 convention • 클래스 멤버변수 operator new의 convention • operator new 또한 상속된다. • 상속받은 클래스가 Base의 operator new를 호출했을 경우를 체크하자. • item 50의 경우처럼 특수한 new를 만들었을 경우 기본 new를 호출할 수 있게 void* Base::operator new (size_t size) throw (bad_alloc) { if( size != sizeof(Base) ) //틀린 크기가 들어오면 기존의 ::operator new사용 return ::operator new( size ); … } • 클래스의 크기는 최소 1이므로 0바이트 체크까지 되는 코드임
  • 24. Item 51: operator new/delete의 convention • operator new[] 에서 convention • 단순히 주어진 사이즈의 메모리 덩어리를 할당하면 된다. • 배열 정보를 함부로 추론하려 하지마라 • 몇 개의 객체가 들어올지 예측할 수 없다. • new를 호출할 파생 클래스 객체의 사이즈를 알 수 없다. • 안다고 해도 new [] 는 실제 객체 * 배열 길이 보다 더 큰 사이즈를 할당한다. • item 16에서 언급한 헤더정보가 추가된다.
  • 25. Item 51: operator new/delete의 convention • operator delete에서 convention • null포인터 exception만 조심하면 된다. void operator delete( void* rawMemory ) throw () { if ( rawMemory == NULL ) return; //NULL delete 방지 //메모리 해제 작업 … }
  • 26. Item 51: operator new/delete의 convention • 클래스 멤버변수 operator delete 에서 convention • 상속받은 클래스가 BASE의 operator delete를 호출하는 경우를 체크하자. void Base::operator delete ( void* rawMemory, size_t size ) throw () { if ( rawMemory == 0 ) return; //NULL 체크 if ( size != sizeof( Base ) ) { ::operator delete( rawMemory ); return; } //메모리 해제 작업 … }
  • 27. 위치지정 new / delete ITEM 52
  • 28. Item 52: 위치지정 new / delete • new 호출의 문제점 • Widget* pw = new Widget(); 1. 메모리 할당을 위해 operater new 호출 2. Widget의 기본생성자 호출 • 메모리 할당은 잘 되었는데 Widget 생성자에서 exception? • 런타임 시스템에서 operator new와 짝이 되는 operator delete를 호출해준다. • 기본형의 경우는 문제없이 Pair로 잘 구성되어 있다. • void operator new(size_t) throw (bad_alloc); • void operator delete(void* rawMemory) throw( ); • 기본형이 아닌 operator new가 문제의 시작 (무엇이 Pair인가?)
  • 29. Item 52: 위치지정 new / delete • 기본형이 아닌 operator new (placement new) • 할당시 log를 찍는 operator new 와 그 짝 delete • void* operator new ( size_t size, ostream& logStream ) throw ( bad_alloc ) • void operator delete ( void* pMemory, size_t size) throw ( ); • 매개변수를 따로 받는 operator new 를 위치지정 new라고 한다. • 자주 사용되던 미리 할당할 메모리 위치를 매개변수로 받는 new에서 시작 void operator new ( size_t size, void* pMemory) throw ( ); • ex : vector의 미사용 공간에 원소 객체를 할당-생성 할 때
  • 30. Item 52: 위치지정 new / delete • 런타임 시스템에서 Pair가 되는 operator delete를 찾는 법 • 추가 매개변수의 개수 및 타입이 똑같은 operator delete를 Pair로 • 위 로그 찍는 operator new/delete 예제에서는 서로 짝이 안 맞는다. • 새로운 operator delete 선언 void operator delete( void* pMemory, ostream& logStream ) throw (); • 이런 operator delete를 위치지정 delete라고 부른다.
  • 31. Item 52: 위치지정 new / delete • 만약 예외처리 없이 일반적으로 delete를 호출한다면? • 런타임 시스템은 기본형의 operator delete를 호출한다. • 위치지정 delete는 위치지정 new의 Pair가 필요할 때만 호출된다. • 따라서 표준형태의 operator delete는 기본으로 항상 마련해야 한다. • 추가적으로 위치지정 new를 썼다면 위치지정 delete도 만들어야 한다.
  • 32. Item 52: 위치지정 new / delete • operator new의 오버라이딩 문제 (이름 가림 이슈) • 이름 문제의 디테일은 item 33 참조 • 전용의 operator new가 다른 operator new들을 가리지 않도록! • Widget 클래스에서 위치지정 new만 선언/정의했다면? Widget* pw = new Widget(); //error! 전역 operator new를 가린다. • 전역에서 유효한 operator new 형태들 • void* operator new(std::size_t) throw (std::bad_alloc); //기본형 new • void* operator new(std::size_t, void*) throw (); // 위치지정 new • void* operator new(std::size_t, const std::nothrow_t&) throw(); //예외 불가 new
  • 33. Item 52: 위치지정 new / delete • 클래스에서 operator new를 정의하려면 • 모든 형태의 operator new및 pair가 되는 operator delete 정의필요 • 미리 operator들을 부를 수 있는 인터페이스 클래스를 만들어두자. class StandardNewDeleteForms { //모든 종류의 operator new들을 선언한 인터페이스 public: static void* operator new(std::size_t size) throw(std::bad_alloc) { return ::operator new(size); } … }
  • 34. Item 52: 위치지정 new / delete • 실제 사용 예 class Widget : public StandardNewDeleteForms { //인터페이스 상속 public: using StandardNewDeleteForms::operator new; //이름영역 공유 using StandardNewDeleteForms::operator delete; //별도의 위치지정 operator new /delete static void* operator new(size_t size, void* pAlloc) throw (bad_alloc); static void operator delete(void* pMemory, void* pAlloc) throw (); }