删除是否需要用于在向量中创建的新数组?

时间:2018-01-14 20:51:45

标签: c++ arrays pointers vector void-pointers

我试图为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();

或者是否需要删除每个新的,如果是,那该怎么办?

4 个答案:

答案 0 :(得分:4)

  

为了清理,我应该使用

data.clear();

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

  

或者需要删除每个新的

是。每次执行new[]表达式时,必须只有一个delete[]。如果没有delete[],则会发生泄漏。

  

如果是这样,那怎么办?

您只需删除每个指针。您必须格外小心,不要意外覆盖或删除该向量的元素而不先删除它。您还必须小心不要多次删除相同的元素(或其副本)。

此外,无法删除指向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的代码管理。您必须注意,只要doubles的元素仍指向它们,就不得销毁shortsdata

答案 1 :(得分:2)

不,这不起作用

很抱歉直接,但使用void*就像你做的那样非常糟糕。这种类似C的快捷方式在C ++中无法正常工作,至少在使用其他基本类型的数组时也是如此!

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

因此,让我们使用帮助程序类来演示错误:

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

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

案例1:使用指针手动分配

将使用以下简单代码创建和销毁数组中分配的每个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>案例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个对象

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

经验法则是删除您使用new分配的所有内容当您传递分配了new[]的数组的引用时,您必须删除它delete[]。但是三思而后行,你正在错误地使用分配的引用....因为你没有将它保存在任何地方,而vector也没有,它只是可以导航另一个容器(如果可迭代)来制作副本所有其他容器元素(这是在一堆中添加多个项目的便利方法),因此您丢失了数组引用并创建了内存泄漏。 **并且您使用的array<void*>double类型不兼容(void*与[{1}}类型不同)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);

但是vector<double> v(another_double_container.begin(), another_double_container.end()); 数组没有这样的迭代器,所以你不能用double []的数组来跟随这种方法。

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