【问题标题】:Why destructor and copy constructor is showing this behavior with array of objects?为什么析构函数和复制构造函数会在对象数组中显示这种行为?
【发布时间】:2019-08-18 18:18:16
【问题描述】:

当使用匿名对象初始化数组时,析构函数显示有效值,但我用对象创建了一个数组,覆盖复制构造函数不调用,并且析构函数显示垃圾值。

我尝试通过显示值来理解这一点,但仍然感到困惑。

class Check{
    private:
        int a;
    public:
        Check()
        {
            this->a = 9999;
            cout << "\n Default Constructor Called \n";
        }
        Check(int i)
        {
            this->a = i;
        }
        Check(const Check & obj)
        {
            cout << "COPY CONSTRUCTOR\n";
        }
        ~Check()
        {
            cout << this->a<<" DESTRUCTOR  \n";
        }
};

Check b[2] = {Check(5),Check(4)};
Check obj1(2);
Check obj2(3);
Check a[2] = {obj1,obj2};

我期待“COPY CONSTRUCTOR”输出 4 次,但它只有两次并且没有垃圾值。实际输出如下:

COPY CONSTRUCTOR 
COPY CONSTRUCTOR 
32649 DESTRUCTOR  
-1330935392 DESTRUCTOR  
3 DESTRUCTOR  
2 DESTRUCTOR  
4 DESTRUCTOR  
5 DESTRUCTOR

【问题讨论】:

  • 垃圾值是因为在复制构造函数中你没有初始化this-&gt;a
  • @M.M 你能告诉我为什么复制构造函数只被调用了 2 次吗?
  • 在每个构造函数中打印a的值,你就会明白为什么了。
  • @EtiennedeMartel 为什么在这种情况下没有调用复制构造函数:Check b[2] = {Check(5),Check(4)};"
  • @usaamw141 这被称为copy elision。对象直接在那里构造,从不复制

标签: c++


【解决方案1】:

原因是因为复制省略。

在这种情况下:

Check b[2] = {Check(5),Check(4)};

由于这两个值都是临时值,因此允许编译器(或者,在 C++17 中,强制)将副本优化掉,而是在原地构造对象。

但是,在第二种情况下:

Check a[2] = {obj1,obj2};

obj1obj2 不是临时的,所以在这种情况下必须出现真实的副本。

【讨论】:

    【解决方案2】:

    在:

    Check b[2] = {Check(5),Check(4)};
    

    这种语法意味着两个数组元素的构造函数参数是 54 。这并不意味着争论是暂时的。

    Check(5) 是一个prvalue 表达式,这并不一定意味着一个临时的被具体化。 prvalue 可以“使用”的一种方式是作为相同类型对象的初始化程序。

    这种行为在 C++17 中有所改变;在此之前,在概念上总是有一个临时的,但编译器可以自行决定是否省略该临时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-22
      • 2018-01-29
      • 2015-12-05
      • 1970-01-01
      • 1970-01-01
      • 2015-04-28
      • 2020-02-29
      相关资源
      最近更新 更多