多线程下的内存管理与单线程下是完全不同的,因为heap是一个可以被全局改动的资源,所以所有的线程都有可能去访问这一资源,这回导致很多的race_conditions。

 
当operator new未取得想要的内存的时候,会调用一个用户指定的处理函数,new_handler。 这个函数可以使用set_new_handler来进行指定。

 namespace std{
typedef void(*new_handler)();//没有参数以及返回值
new_handler set_new_handler(new_handler p) throw();
}
当operator new无法满足内存申请条件的时候,其就会不停的调用new-handler函数,所以说一个设计良好的new-handler应该需要满足下面的要求:
    让更多的内存被使用
    当当前的handler无法满足条件的时候,安装另一个new-handler.
    卸除new_handler,将null指针传给set_new_handler,,此时operator new 在无法分配内存的时候就会抛出异常
    抛出bad_alloc异常:这样的异常会被传播到内存的索求处
    不返回:调用abort或者exit
 
 
当需要以不同的方式去处理不同的class内存分配失败的情况的时候,应该为相应的特殊的class提供自己的set_new_handler以及operator_new。这样operator new会在分配内存的时候确保使用class专属的new_handler替代global的new handler.
 
一个Widget分配资源的简单例子:

 class NewHandlerHolder{
public:
explicit NewHandlerHolder(std::new_handler nh)
:handler(nh){}
~NewHandlerHolder()
std::set_new_handler(handler); //将状态恢复到之前的状态
private:
new_handler handler;
NewHandlerHolder(const NewHandlerHolder &); //禁止这两种操作
NewHandlerHolder & operator(const NewHandlerHolder &);
};

上面这个就可以被自定义的一个类所使用了:

 void * Widget::operator new(std::size_t size) throw (std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));//使用上面的RAII将handler资源正确的管理。
return ::operator new(size);//使用自定义的new
}

实际上,可以将上面的NewHandlerHolder设计成为一个基类模板,这样derived_class科技继承他们需要的set_new_handler以及operator_new,template用于保证每一个derived_class获得一个实体互异的currentHandler成员变量。下为这个模板:

 template<typename T>   //这里的typename T 并未被使用,作用下面会说
class NewHandlerSupport{
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;
};
template<typename T>
static std::new_handler
NewHandlerSupport<T> set_new_handler(std::new_handler p) throw()
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
template<typename T>
static void *
NewHandlerSupport<T>::operator new(std::size_t size) throw(std::bad_alloc)
{
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator(size);//调用全局的operatornew,防止递归的调用自己。
}

有了这个模板,那么为Widget提供专属的set_new_handler以及operator都是很容易的了。继承上面的模板并特例化就可以了:

 class Widget : public NewHandlerSupport<Widget>{
...
};
这样就有了专属的set_new_handler以及operator new。
上买了的typename T 没有被使用,实际上也不需要, 这个T的目的只是为了使得不同的继承自NewHandlerSupport的子类有着其不同的实例函数。(主要是为了static变量,currentHandler)。T只是用来区分不同的derived_class. (因为上面T实例化成了Widget)
 
还有就是关于nothrow的问题,使用new (std::nothrow) Widget不会在new上产生异常,只会返回一个null指针,但是如果new正常还有可能在构造过程中产生异常,因此依然没有异常保证。没事不要用new (std::nothrow) sth;
 
小结:
    set_new_handler允许用户指定一个函数在内存无法分配时调用
    Nothrow new只能保证new不抛异常,构造仍然得不到保证。
 

条款49:了解new-handle行为的更多相关文章

  1. STL笔记(5)条款49:学习破解有关STL的编译器诊断信息

    STL笔记(5)条款49:学习破解有关STL的编译器诊断信息 条款49:学习破解有关STL的编译器诊断信息 用一个特定的大小定义一个vector是完全合法的, vector<int> v( ...

  2. EC读书笔记系列之19:条款49、50、51、52

    条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...

  3. Effective C++ -----条款49:了解new-handler 的行为

    set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用. Nothorw new 是一个颇为局限的工具,因为它只适用于内存分配:后继的构造函数调用还是可能抛出异常.

  4. Effective C++阅读笔记 较详细 复杂条款带样例

    一.让自己习惯C++ 条款01:视C++为一个语言联邦 C++可视为: C:以C为基础. 面向对象的C++:添加面向对象特性. 模板C++:泛型编程概念,使用模板. STL:使用STL的容器.迭代器. ...

  5. 《More Effective C++》 条款5 谨慎定义类型转换函数

    ---恢复内容开始--- C++编译器能够在两种数据类型之间进行隐式转换(implicit conversions),它继承了C语言的转换方法,例如允许把char隐式转换为int和从short隐式转换 ...

  6. 《Effective C++》定制new和delete:条款49-条款52

    条款49:了解new-handler的行为 当operator new无法分配出内存会抛出异常std::bad_alloc 抛出异常前会反复调用用户自定义的new-handler函数直至成功分配内存 ...

  7. Effective C++ 50条款

    条款1:尽量用const和inline而不用#define 以const 行使常量折叠,用inline 代替常用操作的宏定义,而且库里面有很多常用函数可用.当然不能抛弃宏,宏还是很有用滴.偶最近才发现 ...

  8. MoreEffectiveC++Item35 条款27: 要求或禁止对象产生于heap中

    一 要求对象产生在heap中 阻止对象产生产生在non-heap中最简单的方法是将其构造或析构函数声明在private下,用一个public的函数去调用起构造和析构函数 class UPNumber ...

  9. C++异常处理:try,catch,throw,finally的用法

    写在前面 所谓异常处理,即让一个程序运行时遇到自己无法处理的错误时抛出一个异常,希望调用者可以发现处理问题. 异常处理的基本思想是简化程序的错误代码,为程序键壮性提供一个标准检测机制. 也许我们已经使 ...

随机推荐

  1. PyNN:神经网络模拟器的通用接口

    PyNN:神经网络模拟器的通用接口 计算神经科学已经产生了用于模拟神经元网络的多样化软件,同时具有消极和积极的后果.一方面,每个模拟器都使用自己的编程或配置语言,导致将模型从一个模拟器移植到另一个模拟 ...

  2. ABAP f4帮助输入多个值

    *---------------------------------------------------------------------- * INITIALIZATION *---------- ...

  3. Java替换字符串中的占位符

    在开发中,会有动态配置字符串其中的某些字符,如何使用字符中的占位符,并且在代码动态替换占位符实现动态配置字符串! 1.定义字符串时,再string文件添加字符串: 注意!记得要在字符文件中加上这些: ...

  4. asp.net(c#)中String.Empty、NULL、"" 三者到底有啥区别和联系?

    开门见山,首先看下面代码,你认为结果分别是什么? string str = string.Empty; string str1 = ""; string str2 = null; ...

  5. 字典,字符串,元组,字典,集合set,类的初步认识,深浅拷贝

    Python之路[第二篇]:Python基础(一)   入门知识拾遗 一.作用域 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 1==1: name = 'Jaso ...

  6. php异常处理类

    <?php header('content-type:text/html;charset=UTF-8'); // 创建email异常处理类 class emailException extend ...

  7. Matlab 绘图完整入门

    Matlab绘图 强大的绘图功能是Matlab的特点之一,Matlab提供了一系列的绘图函数,用户不需要过多的考虑绘图的细节,只需要给出一些基本参数就能得到所需图形,这类函数称为高层绘图函数.此外,M ...

  8. 【CodeChef】Small factorials(BigInteger笔记)

    You are asked to calculate factorials of some small positive integers. Input An integer t, 1<=t&l ...

  9. 主攻ASP.NET MVC4.0之重生:Jquery Mobile 按钮+对话框使用

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. explicit c++

    C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况 ...