Post List

2015년 1월 4일 일요일

new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘 알아 두자.

void * operator new(std::size_t size) throw(std::bad_alloc)
{
  using namespace std;

  if (size == 0) { size = 1; } // 0바이트 요청에는 1로 간주하고 처리

  while (true) {
    메모리 할당;
    if (할당 성공) return (할당 메모리의 포인터);
    // 할당 실패 -> 현재 new-hander를 찾음
    new_handler globalHandler = set_new_handler(0);
    set_new_handler(globalHandler);

    if (globalHandler) (*globalHandler)();
    else throw std::bad_alloc();
  }
}

void operator delete(void* rawMemory) throw() {
  if (rawMemory == 0) return;
  메모리 해제;
}

 - 반환값이 제대로 되어 있어야 한다.
 - 0바이트가 요구되었을 때조차도 적법한 포인터를 반환해야 한다.
 - 다중스레드 환경에서 사용되는 Code라면 스레드 안전성이 보장되어야 한다. 단일 스레드라면 스레드 안전성을 신경 안쓰는 것이 휠씬 더 빠르다.
 - 무한 루프 안에서 구현을 하며 이 루프를 빠져나오는 유일한 조건은 메모리 할당에 성공하는 것이다.
 - delete 작성시 널 포인터에 대해서 안전성을 보장하라.

 특정 클래스 전용 할당자를 만들때 주의해야 할 것은 그 파생 클래스에 대해서 정상동작 하지 않을 수 있다.

class Base {
public:
  static void * operator new(std::size_t size) throw(std::bad_alloc);
  ...
};

class Derived : public Base { ... };

Derived *p = new Derived; // Base::operator new가 호출 됨 !

 가장 좋은 해결 방법으로는 "틀린" 메모리 크기가 들어왔을 때는 시작부분에서 확인한 후에 표준 operator new를 호출하는 쪽으로 살짝 비켜가게 만들어 주는 것으로 해결이 된다. delete의 경우도 마찬가지다.

class Base {
public:
  static void * operator new(std::size_t size) throw(std::bad_alloc);
  static void operator delete(void *rawMemory, std::size_t size) throw();
  ...
};

void * Base::operator new(std::size_t size) throw(std::bad_alloc) {
  if (size != sizeof(Base)) return ::operator new(size);
  ...
}

void Base::operator delete(void* rawMemory, std::size_t size) throw() {
  if (rawMemory == 0) return;
  if (size != sizeof(Base)) {
    ::operator delete(rawMemory);
    return;
  }
  ...
  return;
}

 * 관례적으로, operator new 함수는 메모리 할당을 반복해서 시도하는 무한 루프를 가져야 하고 메모리 할당 요구를 만족시킬 수 없을 때 new-handle를 호출해야 하며, 0바이트에 대한 대책도 있어야 합니다. 클래스 전용 버전은 자신이 할당하기로 예정된 크기보다 더 큰(틀린) 메모리 블록에 대한 요구도 처리해야 합니다.

 * operator delete 함수는 널 포인터가 들어왔을 때 아무 일도 하지 않아야 합니다. 클래스 전용 버전의 경우에는 예정 크기보다 더 큰 블록을 처리해야 합니다.

댓글 없음:

댓글 쓰기