【问题标题】:while calling a constructor from copy constructor it calls destructor too从复制构造函数调用构造函数时,它也调用析构函数
【发布时间】:2017-02-08 02:37:22
【问题描述】:

我制作了一个使用复制构造函数复制对象的程序。在复制构造函数中,我调用了构造函数来创建内存并复制内容。它在构造函数中成功执行此操作,但在构造函数结束后立即调用析构函数,我得到垃圾值。最后在主函数中,如果我尝试破坏新创建的对象,程序就会崩溃。为什么会这样?

这是代码。

#include<iostream>
using namespace std;

class Test
{
    public:
    int a;
    int *p;

    Test(int a,int b,int c)
    {
        this->a=a;
        p=new int[2];
        p[0]=b;
        p[1]=c;
        cout<<"\n\n "<<this->a<<"   "<<this->p[0]<<"   "<<this->p[1];
    }
    Test(const Test &ob)
    {
        Test(ob.a,ob.p[0],ob.p[1]);
        cout<<"\n\n "<<this->a<<"   "<<this->p[0]<<"   "<<this->p[1];
    }
    void print()
    {
        cout<<"\n\n\n "<<a<<"   "<<p[0]<<"   "<<p[1];
    }
    ~Test()
    {
        cout<<"\n\n\n DESTRUCTOR CALLED "<<endl;
        delete [] p;
    }
};

int main()
{
    Test *ob1=new Test(2,3,4);
    cout<<"\n\n\n  ob2: new object";
    Test *ob2=new Test(*ob1);
    cout<<"\n\n\n ob1";
    (*ob1).print();
    cout<<"\n\n\n ob2";
    (*ob2).print();
    delete ob1;
    delete ob2;
    return 1;
} 

产生输出:

2 3 4

ob2: 新对象 2 3 4

调用了析构函数

9968956 9968956 0

ob1

2 3 4

ob2

9968956 9968956 0

调用了析构函数

调用了析构函数

“然后程序停止工作,即崩溃”......

我了解在这种情况下会发生什么,但请解释一下为什么在删除对象 ob2 时程序会在这种情况下崩溃。 谢谢

【问题讨论】:

  • 您真正想用Test(ob.a,ob.p[0],ob.p[1]); 实现什么?对我来说听起来像是一个 XY 问题。
  • p=new int(2*sizeof(int)); 是做什么的?你的意思可能是p=new int[2];

标签: c++ c++11 constructor copy-constructor


【解决方案1】:

复制构造函数确实什么都不做。 Test(ob.a,ob.p[0],ob.p[1]); 只是创建一个临时的Test,它将立即被销毁。 Test的所有成员根本没有初始化。

你想要delegate constructor,这是一个 C++11 特性。

Test(const Test &ob) : Test(ob.a, ob.p[0], ob.p[1])
{
    cout<<"\n\n "<<this->a<<"   "<<this->p[0]<<"   "<<this->p[1];
}

【讨论】:

  • 补充@songyuanyao的提示答案,当您尝试删除第二个对象时程序崩溃,因为您的类属性“p”从未创建,因此删除会导致崩溃。
  • 如果您不能使用委托构造函数,您仍然可以初始化初始化列表中的各个成员。
【解决方案2】:

这里至少有几个问题。

首先,int* p 是指向单个整数的指针,但您将其视为指向整数数组的指针。 p[1] 不一定是你拥有的内存。

关于您意外的析构函数调用,您的复制构造函数会创建一个临时的Test 对象,当您退出复制构造函数的范围时该对象会被销毁。这就是为什么您在尝试从复制构造创建新对象后立即看到您的析构函数被调用的原因。请参阅@songyuanyao 关于使用委托构造函数的回答。

此外,您对delete 的调用无效,因为它们是在您对return 的调用之后放置的。

最后,正如文体注释,return 0; 通常表示您的程序正常结束。 return &lt;some_nonzero_number&gt;; 通常用于向调用者指示您的程序由于某些错误而结束。

编辑:p=new int(2*sizeof(int)); 仍然不是您想要使用 p 的方式,因为您正在尝试使用它。这只是创建一个指向单个整数的指针,其中整数的值为 2 * 4 = 8。 要正确使用p,您的意思可能是p = new int[2];,在这种情况下,请记住在您的析构函数中使用delete [] p;

【讨论】:

  • 不仅是 ctor 中的 p = new int[2];,还有 dtor 中的 delete[] p;
  • 和复制ctor中的深层副本。或者使用 RAII 避免这一切
  • @LightnessRacesinOrbit OP 尝试进行深度复制,如果他成功调用委托构造函数,并且构造函数正确分配内存。
  • @songyuanyao:是的,这是我们确保发生的“如果”。
猜你喜欢
  • 2013-04-17
  • 2011-04-16
  • 1970-01-01
  • 2021-10-20
  • 1970-01-01
  • 2018-10-17
  • 2013-01-01
  • 2017-07-28
  • 2019-08-07
相关资源
最近更新 更多