动态数组释放(赋值操作符与复制构造函数)



应该在复制构造函数和/或赋值操作符中释放动态数组(在构造函数中分配)吗?

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[]数组(因为它已经在被赋值对象的构造过程中被分配到某个地方)。而且我确实认为在复制构造对象时不需要释放数组,因为它还没有被构造。

问题是,在应用程序验证器下运行上面的应用程序,无论operator=中是否有delete[],都不会显示内存泄漏。在这两种情况下,应用程序运行正常。

那么,我应该在复制构造函数中delete[] xs,赋值操作符,两者都有还是两者都没有?

一般来说,手动内存管理是一个坏的主意。您不应该这样做,您应该选择std::vector<>或其他容器类,除非您有很好的理由不这样做。这表示…

那么,我应该删除复制构造函数中的[]xs,赋值操作符,都删除还是都不删除?

在丢失指向该数组的最后一个指针之前,应该将分配了new[]的数组delete[]。否则,你会漏的。

在实践中,因为你想要删除的数组是由你的类拥有和封装的,这意味着你必须在赋值操作符重载(在指针被赋给一个新数组之前,从而失去对前一个数组的唯一现有引用)和析构函数(当你处理对象,然后失去对封装数组的唯一现有引用)中对它进行delete[]

正如你所说,复制构造函数是一个构造例程,指针先前没有引用任何已分配的资源(事实上,这里没有"先前",对象的生存期甚至还没有开始):因此,这里不仅不需要delete[],它是错误的。

还要注意,为了避免悬空指针和可能的未定义行为,您应该确保您的类确实是封装数组的唯一所有者。否则,类外部的代码可能会delete[]它,或者保存指向它的指针,这将成为悬空。因此,不应该让xs数据成员public .

最新更新