我对C ++中的new
语法位置有疑问。以下两个代码片段在功能上是否相同,并且可以互换使用(我并不是说第二个应该使用,当第一个适合时)?
#1
T* myObj = new T();
// Do something with myObj
delete myObj;
#2
char* mem = new char[sizeof(T)];
T* myObj = new (mem) T();
// Do something with myObj
myObj->~T();
delete[] mem;
当我使用像这样的放置新语法时,我应该特别小心吗?
答案 0 :(得分:11)
它们不是等价的,因为如果T
的构造函数或析构函数抛出它们,它们会有不同的行为。
new T()
将释放已分配的所有内存。 char* mem = new char[sizeof(T)]; T* myObj = new (mem) T();
不会(除非你明确做某事以确保它被释放,否则你会有泄漏)。同样,delete myObj
将始终释放内存,无论~T()
是否抛出。
T* myObj = new T();/*other code*/delete myObj;
的完全等价物如下:
//When using new/delete, T::operator new/delete
//will be used if it exists.
//I don't know how do emulate this in
//a generic way, so this code just uses
//the global versions of operator new and delete.
void *mem = ::operator new(sizeof(T));
T* myObj;
try {
myObj = new (mem) T();
}
catch(...) {
::operator delete(mem);
throw;
}
/*other code*/
try {
myObj->~T();
::operator delete(mem);
}
catch(...) {
//yes there are a lot of duplicate ::operator deletes
//This is what I get for not using RAII ):
::operator delete(mem);
throw;
}
答案 1 :(得分:8)
由于你正在分配原始内存,因此更接近的是:
void *mem = operator new(sizeof(T));
T *myobj = new(mem) T();
// ...
myobj->~T();
operator delete(mem);
请注意,如果您为某个特定班级重载::operator new
,则会使用该班级' operator new
,您使用new char []
的地方会忽略它。
编辑:虽然我应该补充一点,我忽略了例外的可能性。 @ Mankarse的答案似乎(对我而言)能够很好地覆盖这一部分。
答案 2 :(得分:0)
从根本上讲,你在两种情况下都做同样的事情:即你在堆上实例化一个新对象而你正在释放内存,但在第二种情况下,你(显然)正在使用安置新操作员。
在这种情况下,它们都会产生相同的结果,如果构造函数按Mankarse解释的那样抛出差异。
此外,我不会说你可以互换使用它们,因为第二种情况不是placement new
如何使用的现实例子。在内存池的上下文中使用placement new
可能会更有意义,如果您正在编写自己的内存管理器,那么您可以在每个分配的内存上放置多个T
对象(在我的测试中,它倾向于节省大约25%的CPU时间)。如果你有一个更实际的placement new
用例,那么你应该担心更多的事情。
答案 3 :(得分:0)
好吧,你正在为你的T对象预先分配内存。它应该没问题。然而,如果您将再次重用已分配区域,这是有道理的。否则会慢一些。
答案 4 :(得分:0)
是。你的例子太简单了,无法证明这一点,但你预先分配的内存“mem”应该管理存储在“myObj”中的对象。
或许采用更好的方法,方案#1 在堆上分配空间,并在该空间中构造一个对象。场景#2 在堆上分配空间“mem”,然后在该空间内构建对象某处。
现在,在“mem”中将第二个对象放在其他地方。它变得复杂,对吗?
myObj的构建和销毁在两种情况下都是相同的(除了你的构造函数抛出异常的情况,正如Mankarse所指出的那样),但是在方案#1中,分配器正在为你处理你的内存管理,而不是在场景#2中。
因此,请注意妥善管理“mem”。一个common approach如下:
template<class T> void destroy(T* p, Arena& a)
{
if (p) {
p->~T(); // explicit destructor call
a.deallocate(p);
}
}