内存管理 Part 1 — new & placement new & operator new

一、 关于new的故事

首先,看看为什么说在C++中尽量用new/delete而不是malloc/free?

因为new/delete会隐式的调用对象的构造函数和析构函数,第三条用两种方法给一个包含10个string对象的数组分配空间,一个用malloc,另一个用new:

stringstringarray1=

static_cast
<string
>(malloc(10sizeof(string)));



string
stringarray2=newstring[10];

其结果是,stringarray1确实指向的是可以容纳10个string对象的足够空间,但内存里并没有创建这些对象,而且,没有办法来初始化数组里的对象。换句话说,stringarray1其实一点用也没有。相反,stringarray2指向的是一个包含10个完全构造好的string对象的数组,每个对象可以在任何读取string的操作里安全使用。

假设你想了个怪招对stringarray1数组里的对象进行了初始化,那么在你后面的程序里你一定会这么做:

free(stringarray1);

delete [] stringarray2;

调用free将会释放stringarray1指向的内存,但内存里的string对象不会调用析构函数,如果string对象象一般情况那样,自己已经分配了内存,那这些内存将会全部丢失。相反,当对stringarray2调用delete时,数组里的每个对象都会在内存释放前调用析构函数。做如下测试

classTest

{

public:

Test(
intsize=100)

{

_str
=newchar[size];

cout
<<"hold memory in constructor"<<endl;

}

~Test(void)

{

delete[] _str;

cout
<<"release memory in destructor"<<endl;

}

private:

char_str;

};



intmain(void)

{

Test
pTest=newTest[3];

delete[] pTest;



cout
<<"------------------------------------"<<endl;



Test
pTest2=static_cast<Test>(malloc(3*sizeof(Test)));

free(pTest2);



return0;

}

内存管理 Part 1 --- new & placement new & operator new

上面的测试显示了new/delete和malloc/free的区别,如果用new分配了对象然后用free释放有什么后果不难想象。

内存终究是有限的,那么分配内存就可能会失败,在通常自己写的一些小程序里鲜有分配内存失败的情况,但是在分配大块内存、尤其是内存容量较小比如嵌入式系统的时候还是很有可能发生,C语言里分配内存失败的时候就返回一个空值0,所以经常看到有这样的代码:

typep=(type)malloc(size);

if(p==0)...

C语言中这种处理方式是可行的,但是C++中则未必,早期C++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多C++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new以及operator new[]以继续提供返回0功能。这些形式被称为“无抛出”,他们在使用new的入口点采用了nothrow对象,但是在new内存的时候如果不声明nothrow则内存分配失败时会抛出bad_alloc的异常,这时用如上C语言的方式检测成功与否就未必可行,下面的例子在VS2005下进行测试

voidtest(void)

{

unsigned
longsize=150010241024;



charmem1=new(nothrow)char[10size];//若分配失败返回0

if(!mem1)//这个检查可能会成功

{

cout
<<"allocate 1 failed"<<endl;

}



charmem2=newchar[10size];//分配失败抛出std::bad_alloc

if(!mem2)//这个检查一定失败

{

cout
<<"allocate 2 failed"<<endl;

}

}

测试结果是"allocate 1 failed",由于没有处理程序在分配mem2失败时的异常,因此执行到分配mem2的时候崩溃,解决方法是用try{}catch(std::bad_alloc&)捕获内存分配失败的异常。

另外,C++里用set_new_handler来设置失败的处理函数,比如在处理函数里先释放空闲内存然后再次请求内存分配,其形式为
typdefvoid(*new_handler)();

new_handler set_new_handler(new_handler p)
throw();

set_new_handler的形式大致如下, 具体见第七条
new_handler set_new_handler(new_handler p)

{

new_handler old_handler
=current_handler;

current_handler
=p;

returnold_handler;

}

二、placement new

标准C++支持在一分配的内存上构造对象,这一点在构建内存池时很有效

Operator new allocates memory from the heap, on which an object is constructed. Standard C++ also supports placement new operator, which constructs an object on a pre-allocated buffer. This is useful when building a memory pool, a garbage collector or simply when performance and exception safety are paramount (there's no danger of allocation failure since the memory has already been allocated, and constructing an object on a pre-allocated buffer takes less time):

void placement() {

char *buf  = new char[1000];   //pre-allocated buffer
    string *p = new (buf) string("hi");  //placement new
    string *q = new string("hi");  //ordinary heap allocation
    cout<c_str()<c_str();<

可参考的博文:

参加内存池管理

http://www.ecjtu.org/forum/read.php?tid-25583.html

代码实现??

placement new

http://www.cppblog.com/jacky2019/archive/2007/04/06/21375.html

http://www.ecjtu.org/forum/read.php?tid-25583.html

静态快上内存分配(除了不在堆区实际相当于内存池)

http://www.cppblog.com/expter/archive/2009/08/16/93511.aspx
原文链接: https://www.cnblogs.com/cnspace/archive/2010/05/25/AllocMemory.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/11162

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 上午12:52
下一篇 2023年2月7日 上午12:52

相关推荐