new 和 delete要成对使用,且要采取相同形式。
使用new时,会发生2件事,1.内存被分配出来;2.针对此内存会有一个(更多)构造函数被调用;
使用delete,发生2件事,1.针对此内存的析构函数被调用;2.内存被释放;
举例:
std::string * stringPtr1 = new std::string;
std::string * stringPtr2 = new std::string[100];
delete stringPtr1;
delete [] stringPtr2;
开发人员为了研究学习他们的软件使用内存的行为特征,然后修改分配和归还工作,以求获得其所建置的系统的最佳效率
定制new和delete:主角是operator new和 operator delete,配角是new-handler
了解new-handler的行为:
首先介绍客户指定的错误处理函数的使用方法:调用set_new_handler
namespace std{
typedef void (*new_handler) ();------new_handler被定义为函数指针
new_handler set_new_handler(new_handler p) throw(); 返回值是一个指针,指向set_new_handler 被调用前正在执行的那个new-handler函数
}
如何为每一个class 设计专属的new-handlers?需要为class提供自己的set_new_handler和operator new即可。
举例:
class Widget{
public:
static std::new_handlerset_new_handler(std::new_handler p) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handlercurrentHandler;
}
std::new_handler Widget::currentHandler = 0; //Static 成员必须在class 定义式之外定义,除非他们是const且是整数型。
std::new_handler Widget::set_new_handler(std::new_handler p) throw()//标准的set_new_handler
{
std::new_handler oldHandler = currentHandler;
currentHandler = p;
return oldHandler;
}
class NewHandlerHolder{
public:
explicit NewHandlerHolder(std::new_handler nh) : handler(nh){}//防止隐式转换
~NewHandlerHolder(){std::set_new_handler(handler);} //恢复new_handler
private:
std::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_hanlder(currentHandler));//保存全局的handler
return ::operator new(size);
}
//采用模板方式建立一个复用的baseclass,采用的方式是CRTP
请记住:
set_new_handler 允许客户指定一个函数,在内存分配无法获得满足时被调用
Nothrow new是一个颇为局限的工具,因为它只是用内存分配;后继的构造函数调用还是可能抛出异常
了解何时在“全局性的”或“class 专属的”基础上合理体寒缺省的new和delete。
1. 为了检测运用错误
2. 为了收集动态分配内存之使用统计信息
3. 为了增加分配和归还的速度
4.为了降低缺省内存管理器带来的空间额外开销
5.为了弥补缺省分配器重的非最佳齐位
6.为了将相关对象成簇集中
7.为了获得非传统的行为
举例:对heap 运用错误进行调试的定制new和delete开发
http://blog.sina.com.cn/s/blog_65e729050100m7uw.html
编写new和delete时需要固守常规
原则:实现一致性operator new必得返回正确的值;内存不足时必得调用new-handling 函数;
必须有对付零内存需求的准备;避免不慎掩盖正常形式的new
举例:满足前三条
void* operator new(std::size_t size)
{
using namespace std;
if(0 == size){
size = 1;
}
while(true){
void* p = ::operator new(size);
if(null != p) return p;
new_handler globalHandler = set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler) (*globalHandler)();
else throw std::bad_alloc();
}
}
如果涉及到派生类继承要如何处理呢?
calss Base{
public:
static void* operator new(std::size_t size) throw(std::bad_alloc);
static void operator delete(void* rawMemory,std::size_t size) throw();
};
void* Base :: operator new(std::size_t size) throw(std::bad_alloc)
{
if(size != sizeof(base))
return ::operator new(size);
}
void Base::operator delete(void* rawMemory,std::size_t size) throw()
{
if(rawMemory == 0)return ;
if(size != sizeof(Base)){
::operator delete(rawMemory);
return ;
//归还所指的内存
return ;
}
//placement new 和placement delete
placement new的定义如下:
void * operator new(std::size_t, void* pMemory) throw();
步骤一:Widget* pw = new Widget;共有两个函数被调用,1是分配内训的operator new;一个是Widget的默认构造函数
步骤二:
class Widget{
public;
static void* operator new(std::size_t size,std::ostream& logStream)throw (std::bad_alloc);
static void operator delete(void* pMemory,sdd::size_t size)throw();
}
如果内存分配成功,但是在构造函数中失败的话,运行期系统会做内存的处理,它会找寻域operator new
类似的operator delete,否则就会找不到对应的释放参数 而导致内存泄露。
不要掩盖正常的operator, 一定要成对出现。