是否需要将 delete 用于在 vector 中创建的新数组?

Does delete need to be used for new'd arrays created in vector?

我正在尝试为 void** 数据数组创建一些动态数组。

std::vector<void*> data;
data.push_back(new double[1024]);  // array of doubles
data.push_back(new short[1024]);   // array of shorts

为了清理我应该只使用

data.clear();

或者是否需要删除每一个新的(s),如果是,那是怎么做的?

是的,对于您的情况,您必须通过 operator delete 明确释放它们。但是,由于您似乎想存储指向不同类型数组的指针,您打算如何区分它们?

忽略这个事实,您的示例代码尖叫 std::unique_ptr

For clean up should I just use

data.clear();

这将从向量中删除所有指针。如果其中任何一个是指向它们各自动态对象的唯一副本,那么这些对象就不能再被销毁,也不能释放它们的内存。这称为内存泄漏。

Or do each of the new(s) need to be deleted

是的。每执行一次 new[] 表达式,就必须恰好有一个 delete[]。如果没有delete[],则有泄漏

and if so, how is that done?

您只需删除每个指针。您必须格外小心,不要在未先删除该向量的情况下意外覆盖或删除该向量的元素。您还必须注意不要多次删除同一元素(或其副本)。

此外,无法删除指向 void 的指针。指向 void 的指针可以转换为任何数据指针类型,但您必须知道每个元素的类型。一个工作示例

delete[] static_cast<double*>(data[0]);
delete[] static_cast<short* >(data[1]);

存储拥有内存的裸指针通常是一个非常糟糕的主意 - 更何况为此目的使用指向 void 的指针。更好的设计是将动态数组存储在 RAII 容器中,例如 std::vector:

std::vector<double> doubles(1024);
std::vector<short>  shorts (1024);
std::vector<void*>  data{doubles.data(), shorts.data()};

这样数组归向量所有,内存由std::vector的代码管理。你必须注意 doublesshorts 不能被销毁,只要 data 的元素仍然指向它们。

不,这行不通

抱歉直截了当,但像您那样使用 void* 是一种非常糟糕的做法。这种类似于 C 的快捷方式在 C++ 中无法正常工作,至少当您使用其他任何基本类型的数组时不会!

因为将指向对象的指针转换为 void 指针,不允许编译器生成 C++ 对象生命周期所需的代码。

所以让我们使用助手 class 来演示问题所在:

class C1 {
public: 
    C1() { cout<<"  C1 object constructed"<<endl; } 
    ~C1() { cout<<"  C1 object destroyed"<<endl; }
};

Here问题的在线演示,我将在下文中逐步解释。

情况一:用指针手动分配

数组中分配的每一个C1,都会被创建和销毁,代码如下:

C1 *p = new C1[2];   // every new []
delete[] p;          // requires delete[]

案例 2:手动分配推入指针向量:

当向量被破坏或清除时,它的内容也会被破坏或清除。但是,对于指针向量,指针被销毁而不是指向的对象:

所以这行不通;它会泄漏内存:

   vector<C1*> v; 
   v.push_back(new C1[2]);   // C1 objects are created 
   v.clear();                // pointers are lost but C1 objects are not derleted.  

如果在clear之前插入下面的语句,一切又好了:所有创建的C1都被销毁了:

   for (auto &x:v)
       delete[]x; 
   v.clear(); 

案例 3:void* 替代方案注定要失败:

如果我们采用上面的工作代码,但使用转换为 void*,则会创建 C1 对象,但不会销毁它们:

std::vector<void*> data;
data.push_back(new C1[2]);   // yes, creating works and ponter is in ector
for (auto &x:data) 
       delete[]x;           // ouch, deletes a void* so it doesn't know that it's a C1 object
data.clear();

如何解决?

那么,您需要为存储在矢量上的对象设置一个公分母,例如:

  • 对所有元素使用继承和通用基类型。
  • 使用带有类型选择器的联合可以知道指向的对象的类型
  • 使用 boost::variant 个对象

如果你有一个共同的基类型,你可以考虑向量替代向量来摆脱手动内存管理。

经验法则是删除你用new分配的所有东西当你传递一个用new[]分配的数组的引用时,你会必须用 delete[] 删除它。但是三思而后行,你正在错误地使用分配的引用....因为你没有将它保存在任何地方,而且 vector 也没有,它只能导航另一个容器(如果可迭代)来制作副本所有其他容器元素(这是在一堆中添加多个项目的便捷方法),因此您正在丢失数组引用并造成内存泄漏。 **并且您使用的 array<void*>double 类型不兼容(void*double 类型不同) vector 没有一个构造函数,将一个基本类型元素的数组传递给它。它应该有一个像

这样的构造函数吗
vector::vector<T>(const T v[], const size_t sz);

然后你可以初始化一个vector<double>

const double initial[] = { 109.8, 98.5, 87.5 };
const size_t initial_sz = sizeof initial / sizeof initial[0];
vector<double> v(initial, initial_sz);

但是你没有这个构造函数,所以你必须使用另一种方法,比如:

vector<double> v;
v.push_back(109.8);
...
v.push_back(87.5);

of 如果你有另一个可迭代容器,获取迭代器并将其传递给它:

vector<double> v(another_double_container.begin(), another_double_container.end());

但是 double [] 数组没有这样的迭代器,因此您不能对 double 数组使用这种方法。

另一个问题是您尝试在向量中包含不同的类型,但它只允许相同类型的实例。您不能(并且编译器不允许您这样做)将不同的类型存储到一个向量中(因为它像在数组中一样连续存储元素)