zoukankan      html  css  js  c++  java
  • effective c++ 笔记 (49-52)


    //---------------------------15/04/27----------------------------


    //#49   了解newhandler的行为

    {

    /*

        1:operator new操作失败时,它首先会调用new_handler函数来处理,客户可以通过set_new_handler

          的函数来设置new_handler函数。

        2:一个设计良好的new_handler必须做以下事情:

            1>让更多内存可被用:

                程序一开始执行就分配一大块内存,而后当new_handler第一次被调用,将这块内存释放还给程序使用。

            2>安装另一个new_handler

                如果这个handler知道另外一个handler有能力获得更多的内存,就可以选择安装那个handler

            3>卸载new_handler

                一旦没有安装new_handleroperator new会在内存分配不成功时抛出异常。

            4>抛出bad_alloc异常:

                这样的异常会被传播到内存索求处。

            5>不返回:

                通常调用abortexit

        这里有一点很重要:new_handler必须执行以上5个选项之一,因为如果设置了一个没用的new_handler

        比如:void dosomething() { cout<<"error"<<endl;}

        那么系统就会无限执行这条语句了。

        3:设计一个属于classnew_handler

            1>先使用资源管理对象,把class专属的new_handler保存到资源管理对象

            2>重载operator new调用标准的set_new_handler,设置之前保存的的new_handler

              这会将classnew_handler安装为global new_handler

            2>调用global operator new,执行内存分配,如果内存分配失败,global operator new函数会调用

              之前安装的class专属new_handler

            3>资源管理对象会自动恢复global new_handler

        4:设计一个可复用的class用来支持class的专属new_handler                         */

        

        template<class T>

        class NewHandlerSupport

        {

        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;

        };

        

        template<class T>

        std::new_handler

        NewHandlerSupport<T>::set_new_handler(std::new_handler p) throw()

        {

            std::new_handler oldHandler = currentHandler;

            currentHandler = p;

            return oldHandler;

        }

        

        template<class T>

        void* NewHandlerSupport<T>::operator new(std::size_t size)throw(std::bad_alloc)

        {

            NewHandlerHolder h(std::set_new_handler(currentHandler));

            return ::operator new(size);

        }

        template<class T>

        std::new_handler NewHandlerSupport<T>::currentHandler = 0;

        //这里唯一困惑的就是为什么要使用模版,模版的作用就是为了达到一个效果:每一个类都可以有自己的

        //静态变量(currentHandler),不然大家的currentHandler就一样了。

    }


    //#50   了解newdelete的合理替换时机

    {

    /* 

        1:为什么要替换编译器提供的operator newoperator delete

            1>用来检测运用上的错误:

                我们可以在客户请求的大小外(前后)多分配一些内存,用来存放标记。如果delete的时候标记被改变了

                就说明被分配的内存的前面或后面被写了,也就是客户操作越界了。这样就可以检测出错误。

            2>为了强化效能:

                编译器提供的newdeletet为了满足所有人的需求,所以会比较笨重,此时为了需求

                我们可以定制自己的newdelete。这是一个获得重大效能提升的办法之一。

                sgistl中,就把128k以下的内存申请交给自己管理,对128k以上的内存使用malloc处理,原因

                是,系统对于小内存的分配会比较慢(相对于我们自己处理来说,因为它总是要记录一些信息,还要考虑

                产生碎片的问题等等)

            3>为了收集使用上的统计数据:

                收集很多数据:分配区块的大小分布如何?寿命分布如何?是FIFO(先进先出)还是LIFO(后进先出)等等。。。

        2:自己定制operator new 要注意一个问题:

            对齐问题,malloc返回的指针总是对齐的,所以如果我们在malloc返回的指针前面加上int类型大小的标记

            那么,针对double类型来说,它是不对齐的。

        3:总结合适替换newdelete

            1>为了检测运用错误

            2>为了收集动态分配内存之使用统计信息

            3>为了增加分配和归还的速度

            4>为了降低缺省内存管理器带来的空间额外开销

            5>将相关对象放在一起:

                这样有助于提高高速缓存的命中率。

            6>为了获得非传统行为

    */

    }


    //#51   编写newdelete时需固守常规

    {

    /*

        1:记得调用new_handler

        2:为了不把operator new被子类继承,检测一下new需要申请的大小,只要不等于Base,就调用

          全局的new

        3:重载delete的时候记得检查NULL指针,这种情况应该直接返回,因为编译器总是允许delete NULL

    */

    }


    //#52   写了placement new也要写placement delete

    {

    /*  1:写了一个placement operator new的时候,要确定写出了对应的delete版本,不然就会发生内存泄漏。

        2:写了placement版本的new时可能会遮盖正常版本的new,所以要实现正常版本的调用,比如:

            static void* operator new(std::size_t size) throw(std::bad_alloc)

            { return ::operator new(size);}

    }

     


  • 相关阅读:
    将方法作为方法的参数
    远程桌面无响应解决方案(转)
    QQ通信机制(转)
    电脑管家禁止程序修改文档后如何恢复权限
    SQL Sever——远程过程调用失败(0x800706be)
    JavaScript学习笔记之JavaScript调用C#编写的COM组件
    kendoUI 免费部分开发部分经验。
    mongoDB连接信息及生成对应的collection生成代码
    写个匹配某段html dom代码某属性的正则匹配方法
    微信获取用户支付共享地址
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983117.html
Copyright © 2011-2022 走看看