fre*_*low 17 c++ arrays initialization placement-new dynamic-memory-allocation
出于好奇,以下是合法的吗?
X* p = static_cast<X*>(operator new[](3 * sizeof(X)));
new(p + 0) X();
new(p + 1) X();
new(p + 2) X();
delete[] p; // Am I allowed to use delete[] here? Or is it undefined behavior?
Run Code Online (Sandbox Code Playgroud)
同理:
X* q = new X[3]();
(q + 2)->~X();
(q + 1)->~X();
(q + 0)->~X();
operator delete[](q);
Run Code Online (Sandbox Code Playgroud)
我很确定两者都给了UB.
§5.3.4/ 12表示新表达式的数组形式可能会为分配的内存量增加一些任意数量的开销.数组删除可以/可以使用它期望的额外内存来执行某些操作,但不是因为您没有分配它期望的额外空间.至少它通常至少会补偿它预期分配的额外内存量以回到它认为从中返回的地址operator new- 但是由于你没有分配额外的内存或应用了偏移量,所以它会传递一个指向operator delete[]未返回的指针operator new[],导致UB(事实上,甚至在返回的地址开始之前尝试形成地址在技术上是UB).
同一部分说如果它分配额外的内存,它必须将返回的指针偏移该开销量.当/如果operator delete[]使用从新表达式返回的指针调用而不补偿偏移量时,您将operator delete[]使用与返回的指针不同的指针调用,operator new[]再次给出UB.
§5.3.4/ 12是一份非规范性的说明,但我没有看到规范性文本中的任何内容与之相矛盾.
从n3242中的5.3.5 [expr.delete]:
2
[...]
在第二个备选(删除数组)中,delete的操作数的值可以是空指针值或由先前数组new-expression产生的指针值.如果不是,则行为未定义.[...]
这意味着delete[] p,p必须是某种形式的结果new[] p(一个新的表达式),或者0.看到结果operator new没有列在这里,我认为第一种情况是正确的.
我相信第二种情况是好的.从18.6.1.2 [new.delete.array]:
11
void operator delete[](void* ptr) noexcept;[...]
要求: ptr应为空指针或其值应为先前对operator new或operator new [](std :: size_t,const std :: nothrow_t&)的调用所返回的值,该调用尚未通过干扰调用而无效.运营商删除.[...]
(3.7.4.2中有类似的文字[basic.stc.dynamic.deallocation],第3段)
因此,只要de/allocation函数匹配(例如delete[] (new[3] T),格式良好),就不会发生任何不良情况.[或者是吗?见下文 ]
我想我在5.3.4 [expr.new]中跟踪了Jerry警告的规范性文本:
10
new-expression将请求的空间量传递给分配函数,作为std :: size_t类型的第一个参数.该参数不得小于正在创建的对象的大小; 仅当对象是数组时,它可能大于正在创建的对象的大小.[...]
在同一段落中的下面是一个示例(非规范性),它强调实现的新表达式确实可以自由地从分配函数中获取比数组所占用的空间更多的内容(存储std::size_t可用于释放函数的可选参数来到()),他们可以抵消结果.所以所有的赌注都在阵列案例中.非数组的情况似乎很好:
auto* p = new T;
// Still icky
p->~T();
operator delete(p);
Run Code Online (Sandbox Code Playgroud)