zoukankan      html  css  js  c++  java
  • Effective C++ 条款26:尽可能延后变量定义式的出现时间

    1. 考虑到抛异常的情况

    2. “直接在构造函数时指定初值”比“通过default构造函数构造出一个对象然后对它赋值”效率更高,同时“具有明显意义之初值”将变量初始化,还可以附带说明变量的目的。总之就是尽量避免无意义的行为。

    3. 

    // A:w定义于循环外
    Widget w;
    for (int i = 0; i < n; ++i) {
        w = i * 2;
        ...
    }
    
    // B:w定义于循环内
    for (int i = 0; i < n; ++i) {
        Widget w;
        w = i * 2;
        ...
    }

    A : 一个构造 + 一个析构 + n个赋值

    B:n个构造 + n个赋值

    如果对象的一个赋值成本低于一组构造+析构成本,A高效,尤其是n较大时。A造成w的作用域比B大,这是缺点。

    因此除非(1)你知道赋值成本比“构造+析构”成本低,(2)你正在处理代码中效率高度敏感的部分,否则应该用做法B。

     

    ------------------------------------------------------------------------------

    实践:设计一个类CLog用来记录错误日志,可能不会用到,可能是全局都要使用的,希望尽可能延后出现的时机。

    办法1:如果先定义一个指针,CLog* pLog = NULL; 需要时再new出一个对象来,顺便说句,new其实是做了malloc+构造的工作。详见

    下面的链接,讲了很清楚,尽管我不懂汇编。new内部在做些什么----小话c++(6)

    这种办法要考虑new失败的情况。

    办法2:

    CLog* getLog() {

       static CLog log;

       return &log; 

    }

    第一次调用getLog()时CLog的构造函数才会执行。

    C中如 malloc 等分配的内存在堆中分配。初始化了的静态变量和全局变量放在Data段中。未初始化的全局变量和局部静态变量放在Bss段中,更准确的说是在Bss段为它们预留了空间。非静态局部变量是在函数调用过程中暂存在栈上的。因此办法1中new分配内存失败的问题办法2木有。

    但是还是要考虑到多线程的问题,也许可能会在多个线程上同时执行构造函数,导致内存泄露。

    办法3:

    char buf[sizeof(CLog)+ sizeof(int)]; 

    CLog* pLog = NULL; 

    ...

    pLog = new(buf)CLog;

    此为placement new,这办法先分配内存,构造函数则在需要时进行。

     

    ------------------------------------------------------------------------------

    关于placement new,http://blog.csdn.net/zhangxinrun/article/details/5940019

    placement new的作用就是:创建对象(调用该类的构造函数)但是不负责分配内存,而是在已有的内存块上面创建对象。用于需要反复创建并删除的对象上,可以降低分配释放内存的性能消耗。

    placement new 的原型:void* operator new( size_t, void* p ) throw()  { return p; }

    void*p指向一个已经分配好的内存缓冲区的的首地址。

    我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数;而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。

    placement new 使用方法如下:

    1. 缓冲区提前分配

    可以使用堆的空间,也可以使用栈的空间,所以分配方式有如下两种:

    class MyClass {…}; 
    char *buf=new char[N*sizeof(MyClass)+ sizeof(int) ] ; 或者char buf[N*sizeof(MyClass)+ sizeof(int) ];

    2. 对象的构造

    MyClass * pClass=new(buf) MyClass;

    3. 对象的销毁

    一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。

    pClass->~MyClass();

    4. 内存的释放

    如果缓冲区在堆中,那么调用delete[] buf;进行内存的释放;如果在栈中,那么在其作用域内有效,跳出作用域,内存自动释放。

    注意:

    1)        在C++标准中,对于placement operator new []有如下的说明: placement operator new[] needs implementation-defined amount of additional storage to save a size of array. 所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数,或者说数组的大小。 

    2)        使用方法第二步中的new才是placement new,其实是没有申请内存的,只是调用了构造函数,返回一个指向已经分配好的内存的一个指针,所以对象销毁的时候不需要调用delete释放空间,但必须调用析构函数销毁对象。

  • 相关阅读:
    js中两个==和三个===的区别
    软件需求工程解析
    《我们应当怎样做需求分析》阅读笔记
    需求工程阅读笔记03
    个人小软件冲刺05
    个人小软件冲刺04
    需求工程阅读笔记02
    个人小软件冲刺03
    个人小软件冲刺02
    个人小软件冲刺01
  • 原文地址:https://www.cnblogs.com/pure/p/2752797.html
Copyright © 2011-2022 走看看