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



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

请考虑以下代码:

#include<stdio.h>
#include<iostream>
// Case 1
class CFoo
{
public:
CFoo()  { printf("CFoo constructor: user-defined defaultn"); }
~CFoo() { printf("CFoo destructorn"); }
};
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 defaultn"); }
CBar(CBar & other) = delete;
~CBar() { printf("CBar destructorn"); }
};
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 defaultn"); }
CBaz(CBaz & other) { printf("CBaz constructor: user-defined copyn"); }
~CBaz()            { printf("CBaz destructorn"); }
};
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. 为什么我不能像CFoo那样CBar bar1 = CBar();创建CBar实例?

  2. testFoo调用 4 个析构函数。 其中 3 个用于 foo0、foo1 和 foo2。第四名从何而来?testBaz具有相同的结构,但仅调用 3 个析构函数。CFooCBaz之间的唯一区别是CBaz具有用户定义的复制构造函数。

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

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

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

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

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


  1. 4th从何而来?

除了命名对象(变量)之外,还构造了两个临时对象,CFoo()CFoo(foo1)。无论出于何种原因,这些临时人员中只有一个被复制省略进行了优化。

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

这以某种方式影响了优化器。我看不出为什么两个CFoo的临时人员都不能被优化掉,但其中一个不是。对于它的价值,我的编译器确实优化了两者。


附言。CBaz baz1 = CBaz();格式不正确,因为非常量左值引用无法绑定到临时引用。

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

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

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

自 C++17 年以来,随着 guaranties elision,规则发生了变化,并且CBar bar1 = CBar();不需要移动/复制构造函数是可访问的, 这相当于CBar bar1{};.

这是直接初始化:

CFoo foo0;

这是副本初始化:

CBaz baz1 = CBaz();

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

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

相关内容

最新更新