C++析构函数问题与类对象的std :: vector有关

Nig*_*gel 7 c++ memory destructor vector

当我有一个类的std :: vector时,我对如何使用析构函数感到困惑.

所以如果我创建一个简单的类如下:

class Test
{
private:
 int *big;

public:
 Test ()
 {
  big = new int[10000];
 }

    ~Test ()
 {
  delete [] big;
 }
};
Run Code Online (Sandbox Code Playgroud)

然后在我的主要功能中,我执行以下操作:

Test tObj = Test();
vector<Test> tVec;
tVec.push_back(tObj);
Run Code Online (Sandbox Code Playgroud)

当我离开范围时,我在Test的析构函数中遇到运行时崩溃.为什么这样,我怎样才能安全地释放我的记忆?

Pét*_*rök 21

问题是您没有为其定义复制构造函数Test.因此,编译器会为您生成一个默认的复制构造函数,它只复制对象的内容 - 在本例中为int指针.

现在,当您将对象推回到向量中时,它将使用复制构造函数进行隐式复制.这导致两个对象指向相同的int数组!所以最后,两个析构函数尝试删除相同的数组--BANG.

每当你通过指针*定义一个拥有成员的类时,除了析构函数之外,你还必须为它定义一个复制构造函数.更新:和赋值运算符,出于同样的原因(感谢@James :-)

Update2:解决所有这些限制的一个简单方法是定义静态数组而不是动态分配的数组:

class Test
{
private:
  int big[10000];
  // no need for constructors, destructor or assignment operator
};
Run Code Online (Sandbox Code Playgroud)

但是,最佳做法是使用std::vector<int>而不是数组.

*即包含指向具有所有权语义的成员的指针(感谢@Steve Jessop澄清)


Kri*_*son 15

你的问题在这里:

Test tObj = Test();
Run Code Online (Sandbox Code Playgroud)

Test()创建一个临时的Test对象,然后把它复制到tObj.此时,两者tObj和临时对象都big设置为指向数组.然后临时对象被破坏,它会调用析构函数并销毁数组.所以当tObj被破坏时,它会再次尝试销毁已经被破坏的数组.

此外,当tVec它被销毁时,它将破坏其元素,因此已经被破坏的阵列将再次被销毁.

您应该定义一个复制构造函数和赋值运算符,以便Test在复制对象时,复制该big数组,或者具有某种引用计数,以便在销毁所有所有者之前不会销毁它.

一个简单的解决方法是像这样定义你的类:

class Test
{
private:
 std::vector<int> big;

public:
 Test (): big(10000) {}
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不需要定义任何析构函数,复制构造函数或赋值运算符,因为该std::vector<>成员将处理所有内容.(但请注意,这意味着只要复制一个实例,就会分配和复制10,000个字节Test.)

  • @shura:C++中的表达式`Test()`根据定义创建一个临时对象.允许编译器对其进行优化,但通常情况下会创建临时值. (2认同)