是否可以删除未使用新表达式构造的对象?

时间:2018-03-29 01:44:31

标签: c++ c++14 new-operator dynamic-memory-allocation delete-operator

迂腐地说,这可能不行。根据{{​​3}}:

  

如果表达式是其他任何东西,包括它是否是由new-expression的数组形式获得的指针,则行为是未定义的。

暂且不论,以下代码在实践中是否正常(T是非数组,并假设未替换new)?

auto p = (T*)operator new(sizeof(T));
new(p) T{};
delete p;

据说在cppref

  

调用分配函数时,new-expression传递   作为第一个参数请求的字节数   std::size_t,非数组T的确为sizeof(T)

所以我猜这可能还不错。但是,也有人说,自C ++ 14以来,

  

允许新表达式删除或组合分配   通过可替换的分配功能。在省略的情况下,   存储器可以由编译器提供而不需要调用   分配功能(这也允许优化未使用的   新的表达)。在合并的情况下,由a进行分配   可以扩展new-expression E1以提供额外的存储空间   如果满足以下所有条件,则为另一个新表达式E2:[...]

     

请注意,只有new表达式允许此优化   使用,而不是任何其他方法来调用可替换的分配函数:   可以优化delete[] new int[10];,但operator delete(operator new(10));不能。

我不太清楚其影响。那么,这在C ++ 14中是否正常?

为什么我会问这个问题?cppref

有时,内存分配和初始化无法在一个步骤中完成。 您必须手动分配内存,执行其他操作,然后初始化对象, 例如,提供强大的异常安全性。 在这种情况下,如果删除表达式无法在结果指针上使用,则必须手动取消初始化和取消分配,这很乏味。 更糟糕的是,如果采用新表达式和手动方法, 你必须跟踪每个对象使用哪一个。

2 个答案:

答案 0 :(得分:4)

如果您有p = new(p) T{};,假设没有自定义(de)分配函数正在运行,则此代码具有明确定义的行为。 (它可以很容易地对抗这些事情;这样做是留给读者的练习。)

规则是你必须给非数组delete一个指向由非数组new(或这样一个对象的基类(带虚拟析构函数)子对象创建的对象的指针,或空指针)。通过这种改变,你的代码可以做到这一点。

不要求非数组new是非展示形式。不可能,因为您最好能够删除new(std::nothrow) int。这也是一个展示位置 new-expression ,即使人们在谈论“新展示位置”时通常也不会这样做。

delete被定义为导致对释放函数的调用(忽略省略情况,这与此无关,因为 new-expression 调用的唯一分配函数不是可替换的全局分配功能)。如果你设置它以便将无​​效参数传递给该释放函数,那么你将从中获得未定义的行为。但是在这里它传递了正确的地址(如果使用了大小的释放函数,则传递正确的大小),因此它的定义很明确。

答案 1 :(得分:-3)

我没有完全掌握OP的最后一段。显式调用析构函数然后释放指针有什么单调乏味的呢?这就是STL和我见过的任何有信誉的lib一直都在做的事情。是的,您必须跟踪如何分配内存,以便将其解除分配。阅读std :: vector和/或std :: shared_ptr的api文档可以让人熟悉正确的做事方式。 如果您不熟悉显式dtor调用的语法,这里有一个简单的片段:

void * raw_ptr= my_alloc(sizeof(my_type),alignof(my_type));
if (!raw_ptr)
     throw my_bad_alloc();
my_type* ptr {new(raw_ptr) my_type{init_params}};
raw_ptr=nullptr;
    //...
ptr->~my_type();//hello! Is it me you're lookin' for?
if (!my_dealloc(ptr))
     throw my_runtime_error();
ptr=nullptr;