Effectiv C++ (08)

条款49:了解new-handler

Typedef vod (*new_handler)();

New_handler set_new_handler(new_handler p) throw();

传入:operator new无法分配足够内存时被调用的函数。

返回:被调用前正在执行的那个函数。

例如:

Void outOfMem()

{

Cerr << “unable to get enough memory” << endl;

Std::abort();

}

Int main()

{

    Std::set_new_handler(outOfMem);

}

new-handler:

1:让更多内存可被使用。

2删除new-handler。当将null传入给set_new_handler时。一旦没有安装任何new-handler,operator new会在内存分配不成功时抛出异常。

Class Widget{

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;

};

Static 成员必须在class定义式外被定义(除非是const而且是整数型)

Std::new_handler Widget::currentHandler = 0;

 

Static std::new_handler set_new_handler(std::new_handler p) throw()

{

Std::new_handler oldHandler = currentHandler;

currentHandler = p;

return oldHandler;

}

 

operator new:

1:调用标准的set_new_handler,告知Widget的错误处理函数。将widget的new-handler安装为globalnew-handler.

2:调用global operatornew,执行内存分配。如果失败,global operator new调用Widget的new-handler。如果new最终无法分配足够的内存,抛出bad_alloc异常。在此情况下,widget的operator new必须回复原本的new-handler,然后传播异常。

3:如果new能够分配足够内存,new会返回一个指针。Widget的析构函数会管理new-handler,它会自动将new-handler恢复。

Widget* pw1 = new widget;

If (pw1 == 0) // 失败,抛出bad_alloc异常

Widget* pw2 = new (std::nothrow) Widget; // 如果分配失败,返回0

If (pw2 == 0) // 这个测试可能成功,也不绝对

nothrow new只适用于内存分配,后继的构造函数则还是有可能抛出异常。

条款50:new、delete的合理替换时机

1:用来检测运用上的错误。如果将new出的内存,delete时失败,则内存泄露。

如果new的内存,调用了多次delete,导致不确定行为。

2:做自己想做的事。个性化定制。

3:收集统计数据。内存分配的不同运用形态(先进先出、后进先出、随机分配、随机归还?)任何时候使用的最大内存分配量是多少?

Static const int signature = 0xDEADBEEF;

Typedef unsigned char Byte;

Void * operator new(size_t size) throw (bad::alloc)

{

Using namespace std;

Size_t realSize = size + 2 * sizeof(int);

Void *pMem = malloc(realSize);

If (!pMem) throw bad_alloc();

// 将signature写入内存的最前端和最后端

*(static_cast<int*>(pMem)) = signature;

*(reinterpret_cast<int*>(static_cast<Byte*>(pMem) + realSize-sizeof(int))) = signature;

// 返回位于第一个signature后面的内存位置

Return static_cast<Byte*>(pMem) + sizeof(int);

}

对齐:

开源库中的内存管理器。例如boost库中的pool对于分配大量小型对象很有帮助。

需要考虑:可移植性、对齐、线程安全。

条款51:编写new、delete时需要固守常规

Void *operator new(size_t size) throw(bad_alloc)

{

Using namespace std;

If (size == 0)

    Size = 1;

While (true)

{

    分配size个内存块

    If (分配成功)

        Return 指针

    // 分配失败,找到new-handler函数,调用

    New-handler globalHandler = set_new_handler(0);

    Set_new_handler(globalHandler);

    If (globalHander)

         (*globalHandler)();

    Else

        Throw std::bad_alloc;

}

}

 

Class Base

{

Static void * operator new(size_t size) throw(bad_alloc);

Static void operator delete(void * rawMemory, size_t size) throw();

};

void Base::operator delete(void * rawMemory, size_t size) throw()

{

If (rawMemory == 0)

    Return;

If (size != sizeof(Base)

{

    ::operator delete(rawMemory); // 调用全局delete函数

    Return;

}

// 归还内存

Return;

}

如果析构函数不是virtual的,operator delete可能无法正常工作

条款52:placement new、placement delete

Widget *pw = new Widget;

// operator new、Widget的default构造函数

假设new成功而构造函数抛出异常,必须恢复,否则造成内存泄露

系统会自动调用new对应的delete

Class Widget

{

Static void * operator new(size_t size, ostream& logStream) throw(bad_alloc);

Static void operator delete(void * rawMemory, size_t size) throw();

Static void * operator delete(void *rawMemory, ostream& logStream) throw(bad_alloc);

 

};

void Base::operator delete(void * rawMemory, size_t size) throw()

{

If (rawMemory == 0)

    Return;

If (size != sizeof(Base)

{

    ::operator delete(rawMemory); // 调用全局delete函数

    Return;

}

// 归还内存

Return;

}

Void *operator new(size_t size, void *pMemory) throw();

Widget *pw = new(std::cerr) Widget;// 会在调用构造函数抛出异常时造成内存泄露

// 运行期编译器希望找到参数个数和类型都与operator new相同的某个delete,如果找到,就直接调用,否则,什么也不做(不会调用全局delete)

Delete pw;// 调用正常的delete。placement delete只有伴随placement new调用而触发的构造函数出现异常时才被调用。对一个指针调用delete不会调用placement delete

在#include<new>中。用途之一:负责在vector的未使用空间上创建对象。一个特定位置上的new。

提供两个版本的delete:operator delete 和placement delete

 

Class Base

{

Static void * operator new(size_t size, ostream& logStream) throw(bad_alloc);

Static void operator delete(void * rawMemory, size_t size) throw();

};

Base*pb = new Base; // 错误!正常形式的operator new被掩盖。

Base *pb = new (std::cerr) Base; // 调用Base的placement new

 

// 缺省的global下的new:

void * operator new(size_t size) throw(bad_alloc);

void * operator new(size_t size, void *) throw(bad_alloc);

void * operator new(size_t size, const std::nothrow t&) throw(bad_alloc);

如果在class内声明任何new,则会掩盖上述global的new。

对于每一个可用的new,确定对应有一个delete。

Class Base

{

Static void * operator new(size_t size, ostream& logStream) throw(bad_alloc)

{

    Return ::operator new(size);

}

Static void operator delete(void * rawMemory, size_t size) throw()

{

    Return ::operator delete(rawMemory);

}

};

9 杂项讨论

条款53:不要轻易忽视编译器的警告

条款54:熟悉标准程序库

TR1:

1:智能指针

         tr1::shared_ptr        tr1::weak_ptr

2:tr1::function

3:tr1::bind

4:Hash tables:

         实现set、multiset、map、multimap

5:正则表达式

6:Tuples:变量组

tr1::array

tr1::mem_fn

tr1::reference_wrapper

随机数生成

书序特殊函数

type traits:

tr1::result_of:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值