迂腐地说,这可能不行。根据{{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)
有时,内存分配和初始化无法在一个步骤中完成。 您必须手动分配内存,执行其他操作,然后初始化对象, 例如,提供强大的异常安全性。 在这种情况下,如果删除表达式无法在结果指针上使用,则必须手动取消初始化和取消分配,这很乏味。 更糟糕的是,如果采用新表达式和手动方法, 你必须跟踪每个对象使用哪一个。
答案 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;