我应该在复制构造函数和/或赋值运算符中释放动态数组(在构造函数中分配)吗?
struct Test
{
const size_t n;
int* xs;
Test(const size_t n)
: n(n)
, xs(new int[n])
{ }
Test(const Test& other)
: n(other.n)
, xs(new int[n])
{
memcpy(xs, other.xs, n * sizeof(int));
}
Test& operator=(const Test& other)
{
n = other.n;
delete[] xs;
xs = new int[n];
memcpy(xs, other.xs, n * sizeof(int));
}
~Test()
{
delete[] xs;
}
};
void main()
{
Test a(10);
Test b(a);
Test c(20);
c = b;
}
正如你所看到的,我猜你在赋值运算符实现中必须delete[]
数组(因为它已经在构造被赋值的对象的过程中被分配了)。而且我确实认为在复制构造对象时不需要释放数组,因为它尚未构建。
问题是,无论delete[]
中是否有operator=
还是没有delete[] xs
,运行Application Verifier下的应用程序都不会显示内存泄漏。在两种情况下,应用程序都运行正常。
那么,我应该在复制构造函数,赋值运算符中同时使用{{1}}吗?
答案 0 :(得分:0)
一般来说,手动内存管理是一个糟糕的想法。你不应该这样做,你应该更喜欢std::vector<>
或其他容器类,除非你有充分的理由不这样做。这说......
那么,我应该在复制构造函数,赋值运算符中删除[] xs,还是两者都不删除?
在丢失指向该数组的最后一个指针之前,您应该delete[]
一个用new[]
分配的数组。否则,你会泄漏。
实际上,由于你要删除的数组是由你的类拥有和封装的,这意味着你必须在赋值运算符重载delete[]
中(在指针被赋值给新数组之前)因此丢失了对前一个的唯一现有引用)和析构函数(当你处理对象然后丢失对封装数组的唯一现有引用时)。
正如你所说,复制构造函数是一个构造例程,指针以前没有引用任何已分配的资源(事实上,这里没有“先前”,对象的生命周期甚至还没有开始):因此,它这里delete[]
不仅不需要,这是错误的。
另请注意,为了避免悬空指针和可能的未定义行为,您应该确保您的类确实是封装数组的唯一所有者。否则,类外部的代码可以delete[]
,或保存指向它的指针,它将变为悬空。因此,您不应该使xs
数据成员public
。