c++删除指针数组中每个元素指向的对应元素
Deleting corresponding element pointed to by each element of an array of pointer in c++
假设我有一个指针数组声明为:
MyObject** myArr = new MyObject*[someSize] ;
然后我通过
分配一些对象
myArr[i] = myObjectInstance
现在,我想删除这个数组的每个指针指向的每个元素。那么正确的方法是什么?
我认为 delete[] myArr
行不通。
实际上,delete[] myArr
是对的,因为myArr
是动态分配的对象。
如果您在动态分配 myObjectInstance
的地方执行任何 myArr[i] = myObjectInstance
,您可能需要先释放一些 myArr[i]
,例如:
myArr[i] = new MyObject;
delete myArr[i];
在以下情况下会崩溃:
MyObject m;
myArr[i] = &m;
在所有位置都是动态分配的情况下,可以使用for
释放内存:
for (int i = 0; i < someSize; ++i)
delete myArr[i];
for (int i = 0; i < someSize; ++i)
delete myArr[i];
这可以解决问题。不管你怎么做,你都必须访问每个元素并单独删除它,然后用 delete [] myArr;
.
删除数组
但是动态分配数组可能会很麻烦。为了跟上 SO 传统,如果您能够使用它,我将推荐 std::vector
(或任何有意义的 STL 容器)。您仍然需要单独删除所有元素,但现在您不必担心数组本身。
如您问题的评论中所述,如果您对每个元素使用智能指针,则无需手动删除任何内容。
先删除每个对象,然后删除整个数组:
for(int i = 0; i < someSize; i++)
{
delete myArr[i];
}
delete[] myArr;
您可以使用标准算法 std::for_each
和函数对象 std::default_delete
。
这是一个演示程序
#include <iostream>
#include <memory>
#include <algorithm>
struct A
{
static size_t i;
A() { i++; }
~A() { std::cout << --i << ": ~A()\n"; }
};
size_t A::i = 0;
int main()
{
const size_t N = 10;
A **p = new A *[N];
for ( size_t i = 0; i < N; i++ )
{
p[i] = new A();
}
std::for_each( p, p + N, std::default_delete<A>() );
delete []p;
return 0;
}
它的输出是
9: ~A()
8: ~A()
7: ~A()
6: ~A()
5: ~A()
4: ~A()
3: ~A()
2: ~A()
1: ~A()
0: ~A()
如果你想以相对于创建它们的顺序相反的顺序删除数组的元素,那么你可以写
std::for_each( std::reverse_iterator<A **>( p + N ),
std::reverse_iterator<A **>( p ), std::default_delete<A>() );
让我们假设所有 myObjectInstance
都是指向堆分配对象的指针(如果不是这样,请参阅@JoãoPaulo 的回答),并且没有自定义 new
或 delete
涉及。
for (size_t idx = 0; idx < someSize; ++idx)
delete myArr[idx];
delete[] myArr;
潜在的陷阱是什么?
嗯,有很多。如果只初始化了部分数组元素怎么办?另一个将处于不确定状态,删除它们会导致未定义的行为。
另外,如果多个数组元素指向同一个对象怎么办?然后你试图多次删除一个对象。这也会导致未定义的行为。
这并不意味着你不能使用这种幼稚的方法,它只是提醒你一些前提条件:
- 确保数组的每个元素都初始化为 "pointer to some heap allocated object" 或
nullptr
(删除 nullptr
是安全的)。
- 确保您没有删除一个对象两次。
假设我有一个指针数组声明为:
MyObject** myArr = new MyObject*[someSize] ;
然后我通过
分配一些对象myArr[i] = myObjectInstance
现在,我想删除这个数组的每个指针指向的每个元素。那么正确的方法是什么?
我认为 delete[] myArr
行不通。
实际上,delete[] myArr
是对的,因为myArr
是动态分配的对象。
如果您在动态分配 myObjectInstance
的地方执行任何 myArr[i] = myObjectInstance
,您可能需要先释放一些 myArr[i]
,例如:
myArr[i] = new MyObject;
delete myArr[i];
在以下情况下会崩溃:
MyObject m;
myArr[i] = &m;
在所有位置都是动态分配的情况下,可以使用for
释放内存:
for (int i = 0; i < someSize; ++i)
delete myArr[i];
for (int i = 0; i < someSize; ++i)
delete myArr[i];
这可以解决问题。不管你怎么做,你都必须访问每个元素并单独删除它,然后用 delete [] myArr;
.
但是动态分配数组可能会很麻烦。为了跟上 SO 传统,如果您能够使用它,我将推荐 std::vector
(或任何有意义的 STL 容器)。您仍然需要单独删除所有元素,但现在您不必担心数组本身。
如您问题的评论中所述,如果您对每个元素使用智能指针,则无需手动删除任何内容。
先删除每个对象,然后删除整个数组:
for(int i = 0; i < someSize; i++)
{
delete myArr[i];
}
delete[] myArr;
您可以使用标准算法 std::for_each
和函数对象 std::default_delete
。
这是一个演示程序
#include <iostream>
#include <memory>
#include <algorithm>
struct A
{
static size_t i;
A() { i++; }
~A() { std::cout << --i << ": ~A()\n"; }
};
size_t A::i = 0;
int main()
{
const size_t N = 10;
A **p = new A *[N];
for ( size_t i = 0; i < N; i++ )
{
p[i] = new A();
}
std::for_each( p, p + N, std::default_delete<A>() );
delete []p;
return 0;
}
它的输出是
9: ~A()
8: ~A()
7: ~A()
6: ~A()
5: ~A()
4: ~A()
3: ~A()
2: ~A()
1: ~A()
0: ~A()
如果你想以相对于创建它们的顺序相反的顺序删除数组的元素,那么你可以写
std::for_each( std::reverse_iterator<A **>( p + N ),
std::reverse_iterator<A **>( p ), std::default_delete<A>() );
让我们假设所有 myObjectInstance
都是指向堆分配对象的指针(如果不是这样,请参阅@JoãoPaulo 的回答),并且没有自定义 new
或 delete
涉及。
for (size_t idx = 0; idx < someSize; ++idx)
delete myArr[idx];
delete[] myArr;
潜在的陷阱是什么?
嗯,有很多。如果只初始化了部分数组元素怎么办?另一个将处于不确定状态,删除它们会导致未定义的行为。
另外,如果多个数组元素指向同一个对象怎么办?然后你试图多次删除一个对象。这也会导致未定义的行为。
这并不意味着你不能使用这种幼稚的方法,它只是提醒你一些前提条件:
- 确保数组的每个元素都初始化为 "pointer to some heap allocated object" 或
nullptr
(删除nullptr
是安全的)。 - 确保您没有删除一个对象两次。