【发布时间】:2015-06-18 01:03:01
【问题描述】:
为了使用 placement new 而不是自动尝试调用默认构造函数,我使用 reinterpret_cast<Object*>(new char[num_elements * sizeof(Object)]) 而不是 new Object[num_elements] 分配一个数组。
但是,我不确定应该如何删除数组以便正确调用析构函数。我是否应该循环遍历元素,为每个元素手动调用析构函数,然后将数组转换为 char* 并在其上使用 delete[],如下所示:
for (size_t i = 0; i < num_elements; ++i) {
array[i].~Object();
}
delete[] reinterpret_cast<char*>(array);
或者如果我不为每个元素手动调用析构函数就足够了,而仅仅依靠 delete[] 来做到这一点,因为数组的类型是Object*,比如@ 987654329@?
我担心的是,并非每个平台都能以这种方式正确确定数组中的元素数量,因为我没有使用合适的大小。 An answer 对关于“delete[] 如何知道操作数的大小”的问题表示delete[] 的可能实现是存储已分配元素的数量(而不是字节数量)。
如果delete[] 确实以这种方式实现,则表明仅使用delete[] array 会尝试删除太多元素,因为创建数组时使用的char 元素多于适合的Object 元素数量它。所以在这种情况下,删除数组的唯一可靠方法是手动调用析构函数,将数组转换为char*,然后使用delete[]。
但是,实现它的另一种合乎逻辑的方法是以字节为单位存储数组的大小,而不是元素的数量,然后在调用delete[] 时,将数组的大小除以数组通过类型的大小来获取要调用析构函数的元素的数量。如果使用此方法,则只需使用 delete[] array 即可,其中 array 的类型为 Object*。
所以我的问题是:如果数组最初没有分配正确的类型,我可以依靠 delete[] 正确调用操作数数组中元素的析构函数吗?
这是我正在使用的代码:
template <typename NumberType>
NeuronLayer<NumberType>::NeuronLayer(size_t num_inputs, size_t num_neurons, const NumberType *weights)
: neurons(reinterpret_cast<Neuron<NumberType>*>(new char[num_neurons * sizeof(Neuron<NumberType>)])),
num_neurons(num_neurons), num_weights(0) {
for (size_t i = 0; i < num_neurons; ++i) {
Neuron<NumberType> &neuron = neurons[i];
new(&neuron) Neuron<NumberType>(num_inputs, weights + num_weights);
num_weights += neuron.GetNumWeights();
}
}
和
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);
}
【问题讨论】:
-
数组没有析构函数,也没有“数组的放置删除”。您必须记住分配大小并手动调用所有数组元素析构函数。也就是说,这种情况不会真正出现在可移植代码中,因为首先是placement array new is unusable。
-
您的第一个代码块是释放内存的唯一符合标准的方法。
-
@Kerrek SB 你似乎误解了我的问题。我不是在谈论新的放置数组或数组的放置删除。我只使用placement new 来调用类“Neuron”的构造函数来填充数组。我的问题不是关于任何类型的“放置删除”,而是关于如果内存填充了该类型的正确实例,delete[] 是否会正确调用操作数中元素的操作数指针类型的析构函数,即使它不是作为该类型的数组创建的。
-
@RPFeltz:除非
delete[]的操作数的值是先前的array-new 表达式的结果,否则行为是未定义的。reinterpret_cast<char*>(array)显然不是先前的 array-new 表达式的结果(而是 reinterpret-cast 表达式的结果)。 -
@Kerrek SB 你忽略了
array本身是使用new char[num_elements * sizeof(Object)]创建的,所以它实际上是先前array-new 表达式的结果。演员表在那里,因为在创建之后,我将数组转换为Object*,然后再将其存储在字段中。我的问题本质上是不做delete[] reinterpret_cast<char*>(array)的正确行为有多广泛,而在这种情况下只是delete[] array,考虑到array然后具有不同的类型(Object)而不是它创建的(char).
标签: c++ arrays destructor delete-operator placement-new