红色的字体表示(个人认为重点)
绿色字体是我的感想
红色和黑色都是原文哦
条款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一下的啦,以后用到了我还会回来的哦