我试图为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();
或者是否需要删除每个新的,如果是,那该怎么办?
答案 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
的元素仍指向它们,就不得销毁shorts
和data
。
答案 1 :(得分:2)
很抱歉直接,但使用void*
就像你做的那样非常糟糕。这种类似C的快捷方式在C ++中无法正常工作,至少在使用其他基本类型的数组时也是如此!
因为将指向对象的指针强制转换为void
指针,所以不允许编译器生成C ++对象生命周期所需的代码。
因此,让我们使用帮助程序类来演示错误:
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[]
当矢量被破坏或被清除时,其内容也是如此。但是,使用指针的转向器,指针会被破坏,而不是指向的对象:
所以这不起作用;它会泄漏记忆:
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 []
的数组来跟随这种方法。
另一个问题是您尝试在向量中包含不同的类型,并且它只允许相同的类型实例。你不能(并且编译器不允许你这样做)将不同的类型存储到向量中(因为它将元素存储在数组中,连续)