条款49:了解new-handle行为
2024-09-02 04:21:46
多线程下的内存管理与单线程下是完全不同的,因为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不抛异常,构造仍然得不到保证。
最新文章
- 装tomcat和nginx心得
- IAR EW8051-8.10.4安装及破解方法
- selenium如何解决window安全验证问题
- 浅谈JS面向对象之创建对象
- BZOJ3238 [Ahoi2013]差异
- [Linux] Ubuntu Server 12.04 LTS 平台上搭建WordPress(Nginx+MySQL+PHP) Part IV
- 【编程基础】const与#define的区别
- [置顶] android利用jni调用第三方库——第二篇——编写库android程序直接调用第三方库libhello.so
- [转]Libev源码分析 -- 整体设计
- Servlet程序开发-- 取得其他内置对象
- Storm(2015.08.12笔记)
- ABP官方文档翻译 9.1 EntityFramework集成
- (五)java运算
- Filecoin官方更新: Q4工作进展和2018年工作计划
- 盒模型的垂直居中css
- MySQL学习8 - 数据的增删改
- Python_Mix*re模块基础方法,进阶,正则表达式的使用
- Thread线程相关方法详解
- C# 创建 写入 读取 excel
- MVC3学习:利用mvc3+ajax检测用户是否被注册