Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在分配为不同类型的数组上使用delete[]是否安全?_C++_Arrays_Destructor_Delete Operator_Placement New - Fatal编程技术网

C++ 在分配为不同类型的数组上使用delete[]是否安全?

C++ 在分配为不同类型的数组上使用delete[]是否安全?,c++,arrays,destructor,delete-operator,placement-new,C++,Arrays,Destructor,Delete Operator,Placement New,为了使用placement new而不是自动尝试调用默认构造函数,我正在使用reinterpret\u cast(new char[num\u elements*sizeof(Object)]而不是new Object[num\u elements]分配一个数组 但是,我不确定应该如何删除数组以便正确调用析构函数。我是否应该循环遍历元素,为每个元素手动调用析构函数,然后将数组强制转换为char*,并对其使用delete[],如下所示: for (size_t i = 0; i < num_

为了使用placement new而不是自动尝试调用默认构造函数,我正在使用
reinterpret\u cast(new char[num\u elements*sizeof(Object)]
而不是
new Object[num\u elements]
分配一个数组

但是,我不确定应该如何删除数组以便正确调用析构函数。我是否应该循环遍历元素,为每个元素手动调用析构函数,然后将数组强制转换为
char*
,并对其使用
delete[]
,如下所示:

for (size_t i = 0; i < num_elements; ++i) {
     array[i].~Object();
}
delete[] reinterpret_cast<char*>(array);

模板
NeuronLayer::~NeuronLayer(){
删除[]个神经元;
}

模板
NeuronLayer::~NeuronLayer(){
对于(大小i=0;i
以下是管理动态对象数组的可移植代码。它本质上是
std::vector

void * addr = ::operator new(sizeof(Object) * num_elements);
Object * p = static_cast<Object *>(addr);
for (std::size_t i = 0; i != num_elements; ++i)
{
    ::new (p + i) Object(/* some initializer */);
}

// ...

for (std::size_t i = 0; i != num_elements; ++i)
{
    std::size_t ri = num_elements - i - 1;
    (p + ri)->~Object();
}

::operator delete(addr);
void*addr=::运算符new(sizeof(Object)*num_元素);
Object*p=静态_cast(addr);
对于(std::size\u t i=0;i!=num\u元素;++i)
{
::新的(p+i)对象(/*某些初始值设定项*/);
}
// ...
对于(std::size\u t i=0;i!=num\u元素;++i)
{
std::size\u t ri=num\u元素-i-1;
(p+ri)->~Object();
}
::操作员删除(addr);

这是一种常规模式,如果您想拥有非常低级别的控制,您应该如何组织动态存储。结果是,动态数组不应该成为一种语言特性,而应该在库中更好地实现。正如我上面所说,这个代码与现有的标准库小工具几乎相同,这个小工具名为
std::vector

对象*
调用
delete[]
将为
new[]
分配的每个对象调用一次析构函数
newobject[N]
通常在实际数组之前存储N,并且
delete[]
当然知道在哪里查找

您的代码不存储该计数。但它不能,因为它是一个未指定的实现细节,在哪里以及如何存储计数。正如您所推测的,有两种明显的方式:元素计数和数组大小,以及一个明显的位置(在数组之前)。即使如此,也可能存在对齐问题,并且您无法预测用于大小的类型


另外,
newunsignedchar[N]
是一种特殊情况,因为
delete[]
不需要调用
char
的析构函数。在这种情况下,
new[]
根本不需要存储
N
。因此,即使
新对象[N]
将存储一个大小,您甚至不能指望存储该大小。

数组没有析构函数,也没有“数组的位置删除”。您必须记住分配大小并手动调用所有数组元素析构函数。也就是说,这种情况在可移植代码中不可能出现,因为首先,你的第一块代码是唯一符合标准的释放内存的方法。@Kerrek SB你似乎误解了我的问题。我不是在谈论数组的新放置或删除放置。我只使用placement new调用类“Neuron”的构造函数来填充数组。我的问题不是关于任何类型的“placement delete”,而是关于delete[]是否会正确调用操作数中元素上操作数指针类型的析构函数,如果内存中填充了该类型的正确实例,即使它不是作为该类型的数组创建的。@RPFeltz:除非
delete[]
的操作数的值是以前的数组新表达式的结果,否则该行为是未定义的<代码>重新解释强制转换(数组)显然不是先前数组新表达式的结果(而是重新解释强制转换表达式的结果)。@Kerrek SB您忽略了
数组本身是使用
新字符[num_elements*sizeof(Object)]
创建的,因此,它实际上是前一个数组新表达式的结果。之所以存在强制转换,是因为在创建之后,我将数组强制转换为
Object*
,然后将其存储在字段中。我的问题本质上是,考虑到
数组
的类型(
对象
)不同于使用(
字符
)创建的对象,在这种情况下,不执行
删除[]数组
,而只执行
删除[]数组
的正确行为的范围有多广.虽然你在评论中回答了我的问题,指出我的代码会在现有平台上崩溃,但你在这里写的答案并没有真正清楚地回答我的问题。我不会接受它(希望你改进它或者其他人写得更清楚),但我还是给了你一票,因为我不知道有没有可能将一个数字参数传递给
new
,而不是创建一个字符数组。对未来的读者来说:做这种事情时要非常小心!如本回答中所述,存在对齐问题。在您可能遇到的任何平台上,
char
将是1字节,因此将有1字节对齐要求(即无)。然而,
对象
几乎肯定会有更强的对齐要求;违反这一点是未定义的行为,可能会在某些架构(如SPARC)上陷入陷阱;谢谢不过,这个警告仍然适用于大多数其他情况!
template <typename NumberType>
NeuronLayer<NumberType>::~NeuronLayer() {
    delete[] neurons;
}
template <typename NumberType>
NeuronLayer<NumberType>::~NeuronLayer() {
    for (size_t i = 0; i < num_neurons; ++i) {
        neurons[i].~Neuron();
    }
    delete[] reinterpret_cast<char*>(neurons);
}
void * addr = ::operator new(sizeof(Object) * num_elements);
Object * p = static_cast<Object *>(addr);
for (std::size_t i = 0; i != num_elements; ++i)
{
    ::new (p + i) Object(/* some initializer */);
}

// ...

for (std::size_t i = 0; i != num_elements; ++i)
{
    std::size_t ri = num_elements - i - 1;
    (p + ri)->~Object();
}

::operator delete(addr);