c++面向对象之operator new学习笔记

实际的代码中已经不多见到new的身影了,即便是比较老的c++编译器环境, 也提供了auto_ptr管理内存.
可是c++毕竟贴近底层的几个例证就是对类的封装没有增长什么额外的负担,c++对象模型仍然是一一映射到连续的内存地址上去;
对于内存的分配方式, 控制权仍然在程序员手里. 仍是颇有必要熟悉理解一番的.c++

重载operator new好处

  1. 用来检测运行上的错误:好比比较常见的数组越界的段错误, 有时候可能系统不会理解dump掉, 那这个错误就隐藏了.利用这一点能够实现内存泄露.程序员

  2. 提供性能: 这点是最重要的,系统提供的模型内存分配行为一刀切, 而不一样的数据对内存分配器的需求都不同,系统提供的不必定最优.编程

  3. 收集使用统计数据.数组

set_new_handler

operator new同样都是<new>提供, 用于在内存分配失败bad_alloc后调用执行.
系统提供的原型以下, 默认的全局的返回指针为nullptr不会干啥或,若是有须要可重载, 或者放在类的内部.多线程

std::new_handler set_new_handler(new_handler);

通常这个指针std::new_handler不会全局赋值, 若是是这样无疑会影响其余模块, 人家好好的内存分配不了最多来个bad_alloc
全局指针一赋值, 就不知道去哪里去执行啥东西了, 因此, 自用自归还就成了基本原则, 基本流程以下:函数

  1. 获取原始的全局指针new_handler, 存储起来性能

  2. 设置为新的new_handler使用学习

  3. 本身用完了(做用域内/class内), 把最开始保存的归还设置给系统.线程

固然, 这里还涉及多线程的问题, 和当前讨论的不相关, 先不考虑. 这种资源的管理最后归还, 正好可使用类构造/析构函数来完成. 基本形式以下指针

class NewHandlerHolder {
public:
    //构造函数和析构函数共同自动完成了资源的管理.
    explicit NewHandlerHolder(std::new_handler nh) 
        : handler(nh) {}
    ~NewHandlerHolder() {
        std::set_new_handler(handler);
    }   
private:
    std::new_handler handler;
};
 
class Widget 
{
public:
    void *operator new(size_t size) throw(std::bad_alloc);
 
private:
    static std::new_handler currentHandler;
};
 
std::new_handler Widget::currentHandler = 
    [](){
        cout<<"Widget: Unable to satisfy request for memory\n";
        set_new_handler(nullptr);
    };  
 
void *Widget::operator new(size_t size) throw(std::bad_alloc) { 
    cout<<"begin Widget::operator new\n";
    NewHandlerHolder h(std::set_new_handler(currentHandler));
    return ::operator new(size);
}

重载对象operator new

简化版只给出了重启了一个operator new形式,按理说,为了不行为的不一致(有的调用全局有的调用字构建)仍是所有重载比较稳妥

class INTType
{     
public: 
    INTType():x(0) {}
    static void *operator new(size_t size) throw(std::bad_alloc);
      
    //...
private:
    int x;
};

重载对象operator new最佳实践

若是系统中有若干个类都有重载全局operator new的需求, 实际上能够新抽象成一个类做为基类, 子类继承接口便可.
而若是要求不只节省代码, 还要各个类的实例数据独占一份, 能够把类编程模板类,这样子类实例化数据都是独立的.

template<typename T>    // T用于实例化用, 类自己并不使用
class NewHandlerSupport {
public:
    void *operator new(size_t size) throw(std::bad_alloc);
    void *operator new[](size_t size) throw(std::bad_alloc);
 
protected:
    static std::new_handler currentHandler;
};
// 使用类的继承方式
class WidgetHander : public NewHandlerSupport<WidgetHander>

总结

没需求不要重载全局的任何东西,影响范围比较大. 最好放到类中重载
如今对于内存的统计和记录应该都有比较好和成熟的方案, 另外因为智能指针的引入对于内存的使用也不多发生内存泄露等问题
剩下对于operator new重载的强烈需求只来自于性能上的提高, 这方便仍是能够继续深刻学习一下的boost::Pool

参考: <EC49/50/51/52>

相关文章
相关标签/搜索