Effective C++ 总结2 内存管理 (条款5 - 10)
2010-12-06 14:51
381 查看
5. 对应的new和delete要采用相同的形式
用new的时候会发生两件事。首先,内存被分配(通过operator new 函数),然后,为被分配的内存调用一个或多个构造函数。
用delete的时候,也有两件事发生:首先,为将被释放的内存调用一个或多个析构函数,然后,释放内存(通过operator delete 函数)。
对于 delete来说会有这样一个重要的问题:内存中有多少个对象要被删除?答案决定了将有多少个析构函数会被调用。
用new的时候会发生两件事。首先,内存被分配(通过operator new 函数),然后,为被分配的内存调用一个或多个构造函数。
用delete的时候,也有两件事发生:首先,为将被释放的内存调用一个或多个析构函数,然后,释放内存(通过operator delete 函数)。
对于 delete来说会有这样一个重要的问题:内存中有多少个对象要被删除?答案决定了将有多少个析构函数会被调用。
string *stringptr1 = new string; string *stringptr2 = new string[100]; ... delete stringptr1;// 删除一个对象 delete [] stringptr2;// 删除对象数组
6. 析构函数里对指针成员调用delete
增加一个指针成员意味着几乎都要进行下面的工作: ·在每个构造函数里对指针进行初始化。对于一些构造函数,如果没有内存要分配给指针的话,指针要被初始化为0(即空指针)。(构造函数 拷贝构造函数) ·删除现有的内存,通过赋值操作符分配给指针新的内存。 (赋值函数) ·在析构函数里删除指针。 (析构函数)
7. 预先准备好内存不够的情况
1) operator new在无法完成内存分配请求时会抛出异常 std::bad_alloc
2) 当内存分配请求不能满足时,调用你预先指定的一个出错处理函数。这个方法基于一个常规,即当operator new不能满足请求时,会在抛出异常之前调用客户指定的一个出错处理函数——一般称为new-handler函数
3) 指定出错处理函数时要用到set_new_handler函数, operator new不能满足内存分配请求时,new-handler函数不只调用一次,而是不断重复,直至找到足够的内存。
// function to call if operator new can't allocate enough memory void nomorememory() { cerr << "unable to satisfy request for memory/n"; abort(); } int main() { set_new_handler(nomorememory); int *pbigdataarray = new int[100000000]; ... }[/code]
4) 一个设计得好的new-handler函数必须实现下面功能中的一种。 ·产生更多的可用内存。
·安装另一个不同的new-handler函数。
·卸除new-handler。
·抛出std::bad_alloc或从std::bad_alloc继承的其他类型的异常。
正确写法
class x { public: static new_handler set_new_handler(new_handler p); static void * operator new(size_t size); private: static new_handler currenthandler; }; new_handler x::currenthandler; //缺省设置currenthandler为0(即null) new_handler x::set_new_handler(new_handler p) { new_handler oldhandler = currenthandler; currenthandler = p; return oldhandler; } void * x::operator new(size_t size) { new_handler globalhandler = // 安装x的new_handler std::set_new_handler(currenthandler); void *memory; try { // 尝试分配内存 memory = ::operator new(size); } catch (std::bad_alloc&) { // 恢复旧的new_handler std::set_new_handler(globalhandler); throw; // 抛出异常 } std::set_new_handler(globalhandler); // 恢复旧的new_handler return memory; } int main() { x::set_new_handler(nomorememory); x *px1 = new x; string *ps = new string; x::set_new_handler(0); x *px2 = new x; return 0; }[/code]
6) operator new 不抛出异常
class widget { ... };
widget *pw2 = new (nothrow) widget;
8. 写operator new和operator delete时要遵循常规
1) 有关返回值的部分很简单。如果内存分配请求成功,就返回指向内存的指针;如果失败,则遵循条款7的规定抛出一个std::bad_alloc类型的异常。2) operator new实际上会不只一次地尝试着去分配内存,它要在每次失败后调用出错处理函数,还期望出错处理函数能想办法释放别处的内存。只有在指向出错处理函数的指针为空的情况下,operator new才抛出异常。 这样,非类成员形式的operator new的伪代码看起来会象下面这样:void * operator new(size_t size) // 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(); } }
条款7提到operator new内部包含一个无限循环,上面的代码清楚地说明了这一点——while (1)将导致无限循环。
跳出循环的唯一办法是
内存分配成功或
出错处理函数完成了条款7所描述的事件中的一种:
得到了更多的可用内存;
安装了一个新的new-handler(出错处理函数);
卸除了new-handler;
抛出了一个std::bad_alloc或其派生类型的异常;
或者返回失败。
9. 避免隐藏标准形式的new
1) 为class重载operator new必须是static
正确写法class x { public: void f(); static void * operator new(size_t size, new_handler p); 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 = new x; // 调用 x::operator // new(size_t)
另外一个正确写法class x { public: void f(); static void * operator new(size_t size, // p缺省值为0 new_handler p = 0); // }; x *px1 = new (specialerrorhandler) x; // 正确 x* px2 = new x; // 也正确
10. 如果写了operator new就要同时写operator delete
1) operator delete想弄清它要释放的内存有多大,就必须知道当初operator new分配的内存有多大。有一种常用的方法可以让operator new来告诉operator delete当初分配的内存大小是多少,就是在它所返回的内存里预先附带一些额外信息,用来指明被分配的内存块的大小。也就是说,当你写了下面的语句,
airplane *pa = new airplane;
你不会得到一块看起来象这样的内存块:
pa——> airplane对象的内存
而是得到象这样的内存块:
pa——> 内存块大小数据 + airplane对象的内存
2) 如果只写operator new 但是不写operator delete,那么会出现调用类自己写的operator new,但是却调用了全局的operator delete
相关文章推荐
- 内存管理——(exceptional C++ 条款9,条款10)
- Guru of the Week 条款10:内存管理(下篇)
- Effective C++ 条款10解读: 令operator= 返回一个reference to *this
- C++中的内存管理——对effective c++第二章的总结
- effective C++ 条款 10:operator= 返回一个reference to *this
- Effective C++ 条款总结 读书笔记(二)
- Effective C++ -----条款10: 令operator=返回一个reference to *this
- 《Effective C++》学习笔记条款10 令operator= 返回一个reference to *this
- 《Effective C++》构造/析构/赋值 函数:条款10-条款12
- 黑马程序员_ios基础总结10_内存管理
- Effective C++ 条款10: 令operator= 返回一个reference to *this
- Effective C++:条款10:令operator=返回一个reference to *this。
- Effective C++ 条款10 令operator=返回一个reference to *this 条款11 在operator=中处理"自我赋值"
- Effective C++ 总结3 构造函数,析构函数和赋值操作符 (条款11 - 17)
- effective c++ 条款23总结: 必须返回一个对象时不要试图返回一个引用
- Effective C++ 条款总结 读书笔记(一)
- Effective C++ 总结4 类和函数:设计与声明 (条款18 - 28)
- Effective C++ 条款10
- 读书笔记《Effective C++》条款10:令operator=返回一个reference to *this
- Effective C++ 条款总结