Back
Featured image of post Customize new and delete

Customize new and delete

from the start to the end

Understand the behavior of the new-handler

operator new 无法满足某一内存分配需求时,它会抛出异常。

#include <new>
namespace std {
    typedef void (*new_handler)();
    new_handler set_new_handler(new_handler p) throw();
}

void out_of_memory() {
  std::cerr << "unable to satisfy request for memory.\n";
  std::abort();
}

// 当operator new无法满足内存申请时,会不断调用 new-handler 直到找到足够内存
int main() {
  std::set_new_handler(out_of_memory);
  int* pBigData = new int[10000000000];
}

一个优秀的 new-handler 函数需要:

  • 让更多内存可被使用
  • 安装另一个 new-handler
  • 卸除 new-handler
  • 抛出 bad_alloc (或派生自 bad_alloc )的异常
  • 不返回 abort() or exit()

令一个 class 提供自己的set_new_handleroperator new,就可以获得该 class 专属的 new-handler

class Widget {
public:
    static std::new_handler set_new_handler(std::new_handler p) throw();
    static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
    static std::new_handler currentHandler;
};

std::new_handler Widget::currentHandler = 0;

std::new_handler Widget::set_new_handler(std::new_handler nh) throw() {
  std::new_handler oldHandler = currentHandler;
  currentHandler = nh;
  return oldHandler;
}

// RAII 管理 new_handler
class NewHandlerHolder {
public:
    explicit NewHandlerHolder(std::new_handler nh) : handler(nh) {}
    ~NewHandlerHolder() { std::set_new_handler(handler); }

private:
    std::new_handler handler;
    NewHandlerHolder(const NewHandlerHolder&);
    NewHandlerHolder& operator=(const NewHandlerHolder&);
};

// 模板化
template <typename T>
class NewHandlerSupport {
public:
    static std::new_handler set_new_handler(std::new_handler nh) throw();
    static void* operator new(std::size_t size) throw(std::bad_alloc);

private:
    std::new_handler current_handler;
};

template <typename T>
std::new_handler NewHandlerSupport<T>::set_new_handler(
    std::new_handler nh) throw() {
    std::new_handler old = current_handler;
    current_handler      = nh;
    return old;
}

template <typename T>
void* NewHandlerSupport<T>::operator new(std::size_t size) throw(
    std::bad_alloc) {
    NewHandlerHolder h(std::set_new_handler(current_handler));
    return ::        operator new(size);
}

template <typename T>
std::new_handler NewHandlerSupport<T>::current_handler = 0;

Understand when it makes sense to replace new and delete

替换编译器提供的 operator newoperator delete 的几种理由:

  • 用来检测运用上的错误
  • 为了强化效能
  • 为了收集使用上的统计数据
  • 为了增加分配和归还的速度
  • 为了降低缺省内存管理器带来的空间额外开销
  • 为了弥补缺省分配器中的最佳齐位
  • 为了将相关对象成簇集中
  • 为了获得非传统的行为

Adhere to convention when writting new and delete

operator new:实现一致性 operator new 必须返回正确的值,内存不足时必要调用new-handler函数,必须又对付零内存需求的准备,还需避免不慎掩盖非正常形式的 new。

void* operator new(std::size_t size) throw(std::bad_alloc) {
  using namespace std;
  if (size == 0) {
    size = 1;
  }
  void* p;
  while (true) {
    if ((p = malloc(size))) {
      return p;
    }
    new_handler global_handler = set_new_handler(0);
    set_new_handler(global_handler);

    if (global_handler) {
      (*global_handler)();
    } else {
      throw std::bad_alloc();
    }
  }
}
  • operator new 应该内含一个无穷循环,并在其中尝试分配内存,如果无法满足内存需求,就该调用 new-handler。它也应该有能力处理 0 bytes 申请。 Class 专属版本还应该处理 “比正确大小更大的(错误)申请”。
  • operator delete 应该在收到 null 指针时不做任何事。

其他的一些讨论

Pay attention to compiler warnings

Familiarize yourself with the standard library, including TR1

Before TR1:

  • STL
  • IOStream
  • i18n
  • numeric
  • exception hierarchy
  • C89

TR1:

  • smart pointers
  • tr1::function
  • tr1::bind
  • hash tables
  • regular expression
  • tuples
  • tr1::array
  • tr1::mem_fn
  • tr1::reference_wrapper
  • random number
  • math functions
  • C99
  • type traits
  • tr1::result_of

Familiarize yourself with Boost

Licensed under CC BY-NC-SA 4.0
The older I get, the more I realize that most of life is a matter of what we pay attention to, of what we attend to [with focus].
Built with Hugo
Theme Stack designed by Jimmy