是否需要将 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
的代码管理。你必须注意 doubles
和 shorts
不能被销毁,只要 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
数组使用这种方法。
另一个问题是您尝试在向量中包含不同的类型,但它只允许相同类型的实例。您不能(并且编译器不允许您这样做)将不同的类型存储到一个向量中(因为它像在数组中一样连续存储元素)
我正在尝试为 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
的代码管理。你必须注意 doubles
和 shorts
不能被销毁,只要 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
数组使用这种方法。
另一个问题是您尝试在向量中包含不同的类型,但它只允许相同类型的实例。您不能(并且编译器不允许您这样做)将不同的类型存储到一个向量中(因为它像在数组中一样连续存储元素)