effective C++学习文档(2)

来源:互联网 发布:男士包品牌 知乎 编辑:程序博客网 时间:2024/04/28 15:09

红色的字体表示(个人认为重点)

绿色字体是我的感想

红色和黑色都是原文哦

条款6:析构函数里对指针成员调用delete

大多数情况下,执行动态内存分配的的类都在构造函数里用new分配内存,然后在析构函数里用delete释放内存

 

 

如果在析构函数里没有删除指针,它不会表现出很明显的外部症状。相反,它可能只是表现为一点微小的内存泄露,并且不断增长,最后吞噬了你的地址空间,导致程序夭折。因为这种情况经常不那么引人注意,所以每增加一个指针成员到类里时一定要记清楚。

 

 

另外,删除空指针是安全的(因为它什么也没做)。所以,在写构造函数,赋值操作符,或其他成员函数时,类的每个指针成员要么指向有效的内存,要么就指向空,那在你的析构函数里你就可以只用简单地delete掉他们,而不用担心他们是不是被new过。

 

除非类成员最初用了new,否则是不用在析构函数里用delete的。比如智能指针是不用手动删除的:auto_ptr

 

 

条款7:预先准备好内存不够的情况

operator new在无法完成内存分配请求时会抛出异常

 

 

目前看来我还遇不到类似的情况,以后回来补上

 

 

条款8: 写operator new和operator delete时要遵循常规

重写operator new方法

自己重写operatornew时(条款10解释了为什么有时要重写它),很重要的一点是函数提供的行为要和系统缺省的operator new一致。实际做起来也就是:要有正确的返回值;可用内存不够时要调用出错处理函数(见条款7);处理好0字节内存请求的情况。此外,还要避免不小心隐藏了标准形式的new

 

operator new实际上会不只一次地尝试着去分配内存,它要在每次失败后调用出错处理函数,还期望出错处理函数能想办法释放别处的内存。只有在指向出错处理函数的指针为空的情况下,operatornew才抛出异常。

所以个人认为“new”还是很偷懒的,小错它不管的,只有捅破天了它才会出来

C++中内存的操作使用还是很重要的,但是我目前才疏学浅,更本还没用到过- -,先大致看一下吧。。。

 

 

c++标准要求,即使在请求分配0字节内存时,operatornew也要返回一个合法指针

void * operator new(size_tsize)        // operator new还可能有其它参数
{                                      

  if (size == 0){                     // 处理0字节请求时,
    size =1;                          // 把它当作1个字节请求来处理
 }                                    
  while (1) {
    分配size字节内存;

    if (分配成功)
      return (指向内存的指针);

    // 分配不成功,找出当前出错处理函数
    new_handler globalhandler = set_new_handler(0);
    set_new_handler(globalhandler);

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

当中省略…………用的不多不感兴趣啊。我直接看一下总结吧

 

可见,有关operator new和operator delete(以及他们的数组形式)的规定不是那么麻烦,重要的是必须遵守它。只要内存分配程序支持new-handler函数并正确地处理了零内存请求,就差不多了;如果内存释放程序又处理了空指针,那就没其他什么要做的了。至于在类成员版本的函数里增加继承支持,那将很快就可以完成。

 

 

条款9: 避免隐藏标准形式的new

书上有一个形象生动的例子:

 

因为内部范围声明的名称会隐藏掉外部范围的相同的名称,所以对于分别在类的内部

和全局声明的两个相同名字的函数f来说,类的成员函数会隐藏掉全局函数:

voidf();                            // 全局函数

class x {
public:
  voidf();                          // 成员函数
};

x x;

f();                                 // 调用 f

x.f();                               // 调用 x::f

这不会令人惊讶,也不会导致混淆,因为调用全局函数和成员函数时总是采用不同的

语法形式。然而如果你在类里增加了一个带多个参数的operator new函数,结果就有

可能令人大吃一惊。

class x {
public:
  void f();

  // operator new的参数指定一个
  // new-hander(new的出错处理)函数
  static void * operator new(size_t size, new_handler p);
};

voidspecialerrorhandler();          //定义在别的地方

x *px1 =
  new (specialerrorhandler) x;       // 调用x::operator new

x *px2 = newx;                     // 错误!

在类里定义了一个称为“operator new”的函数后,会不经意地阻止了对标准new的访

问。条款50解释了为什么会这样,这里我们更关心的是如何想个办法避免这个问题。

一个办法是在类里写一个支持标准new调用方式的operator new,它和标准new做同样

的事。这可以用一个高效的内联函数来封装实现

 

class x {
public:
  void f();

  static void * operator new(size_t size, new_handlerp);

  static void * operator new(size_t size)
  { return ::operator new(size); }
};

x *px1 =
  new (specialerrorhandler) x;      // 调用 x::operator
                                   // new(size_t, new_handler)

x* px2 = newx;                    // 调用 x::operator
                                   // new(size_t)

另一种方法是为每一个增加到operator new的参数提供缺省值(见条款24):

class x {
public:
  void f();

  static
    void * operator new(size_tsize,               // p缺省值为0
                       new_handler p = 0);         //
};

x *px1 = new (specialerrorhandler)x;              // 正确

x* px2 = newx;                                    // 也正确

无论哪种方法,如果以后想对“标准”形式的new定制新的功能,只需要重写这个函数。

调用者重新编译链接后就可以使用新功能了。

哈哈,显然这个是要MARK一下的啦,以后用到了我还会回来的哦