为什么删除复制构造函数会影响用户定义的默认构造函数?

时间:2017-09-15 17:05:44

标签: c++ constructor copy destructor

学习C ++,对构造函数几乎没有疑问。

请考虑以下代码:

#include<stdio.h>
#include<iostream>

// Case 1

class CFoo
{
public:
    CFoo()  { printf("CFoo constructor: user-defined default\n"); }
    ~CFoo() { printf("CFoo destructor\n"); }
};

void testFoo()
{
    CFoo foo0;              // A way to use default constructor
    CFoo foo1 = CFoo();     // Another way to use default constructor
    CFoo foo2 = CFoo(foo1); // Using implicit copy constructor

    // Output:
    //     CFoo constructor: user-defined default
    //     CFoo constructor: user-defined default
    //     CFoo destructor
    //     CFoo destructor
    //     CFoo destructor
    //     CFoo destructor
}

// Case 2

class CBar
{
public:
    CBar() { printf("CBar constructor: user-defined default\n"); }
    CBar(CBar & other) = delete;
    ~CBar() { printf("CBar destructor\n"); }
};

void testBar()
{
    CBar bar0;
    // line 44: error C2280: 'CBar::CBar(CBar &)': attempting to reference a deleted function
    // line 34: note: see declaration of 'CBar::CBar'
    // line 34: note: 'CBar::CBar(CBar &)' : function was explicitly deleted
    // CBar bar1 = CBar(); // Why this has anything to do with the copy constructor?

    // Output:
    //     CBar constructor: user-defined default
    //     CBar destructor
}

// Case 3

class CBaz
{
public:
    CBaz()             { printf("CBaz constructor: user-defined default\n"); }
    CBaz(CBaz & other) { printf("CBaz constructor: user-defined copy\n"); }
    ~CBaz()            { printf("CBaz destructor\n"); }
};

void testBaz()
{
    CBaz baz0;
    CBaz baz1 = CBaz();
    CBaz baz2 = CBaz(baz1);

    // Output:
    //     CBaz constructor: user-defined default
    //     CBaz constructor: user-defined default
    //     CBaz constructor: user-defined copy
    //     CBaz destructor
    //     CBaz destructor
    //     CBaz destructor
}

// main

void main() {
    testFoo();
    testBar();
    testBaz();

    std::cin.get();
}

问题:

  1. 为什么我无法像CBar那样创建CBar bar1 = CBar(); CFoo的实例?

  2. testFoo调用4个析构函数。其中3个用于foo0,foo1和foo2。 4号来自哪里? testBaz具有相同的结构,但只调用3个析构函数。 CFooCBaz之间的唯一区别是CBaz具有用户定义的复制构造函数。

3 个答案:

答案 0 :(得分:2)

  
      
  1. 为什么我无法像CBar一样创建CBar bar1 = CBar(); CFoo的实例?
  2.   

删除CBar的复制构造函数。因此CBar不可复制。因此,您无法复制初始化CBar

CFoo是可复制的,所以没有问题。

CBar bar1 = CBar(); // Why this has anything to do with the copy constructor?

T object = other;是复制初始化的语法。

  
      
  1. 第四个来自哪里?
  2.   

除了命名对象(变量)之外,还构造了两个临时对象CFoo()CFoo(foo1)。无论出于何种原因,只有其中一个临时演员被复制完毕。

  

testBaz具有相同的结构,但只调用3个析构函数。

这在某种程度上影响了opimizer。我认为没有理由为什么两个CFoo的临时演员都不能被优化掉,但其中一个不是。对于它的价值,我的编译器确实优化了两者。

PS。 CBaz baz1 = CBaz();格式错误,因为非const值左侧引用无法绑定到临时值。

PPS。 void main()格式不正确,因为main必须返回int

答案 1 :(得分:2)

CBar bar1 = CBar();不是分配,而是使用复制/移动构造函数初始化。

即使省略,也应该可以访问移动/复制构造函数。

自从C ++ 17以来,在保证省略的情况下,规则发生了变化,并且 CBar bar1 = CBar();不要求移动/复制构造函数可访问,  它等同于CBar bar1{};

答案 2 :(得分:1)

这是直接初始化:

CFoo foo0;

这是复制初始化:

CBaz baz1 = CBaz();

由于copy elision,复制初始化在性能方面等同于直接初始化,但在语义方面则不同;复制初始化仍需要一个可访问的复制构造函数。

四个析构函数打印输出中的两个来自使用CFoo的默认复制构造函数构造的实例。请注意,打印输出的数量取决于优化:当启用复制省略优化时,可以优化对中间案例(即CFoo foo1 = CFoo())的复制构造函数的调用,因此您将获得三个打印输出,而不是四个。 CFoo foo2 = CFoo(foo0)右侧的副本未进行优化。