为什么删除复制构造函数会影响用户定义的默认构造函数?
Why deleting copy constructor affects user-defined default constructor?
正在学习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();
}
问题:
为什么我不能像 CFoo
那样创建 CBar
的实例 CBar bar1 = CBar();
?
testFoo
调用 4 个析构函数。其中 3 个用于 foo0、foo1 和 foo2。 4th从哪里来? testBaz
具有相同的结构,但只调用了 3 个析构函数。 CFoo
和 CBaz
之间的唯一区别是 CBaz
具有用户定义的复制构造函数。
- Why I can't create an instance of
CBar
as CBar bar1 = CBar();
as I did with CFoo
?
CBar
的复制构造函数被删除。因此 CBar
不可复制。因此你不能复制初始化一个 CBar
.
CFoo
是可复制的,所以没有问题。
CBar bar1 = CBar(); // Why this has anything to do with the copy constructor?
T object = other;
是复制初始化的语法。
- Where does 4th come from?
除了命名对象(变量)外,还构造了两个临时对象,CFoo()
和CFoo(foo1)
。无论出于何种原因,这些临时文件中只有一个被复制省略优化掉了。
testBaz
has the same structure, but only invokes 3 destructors.
这在某种程度上影响了优化器。我看不出为什么两个 CFoo` 临时对象都不能被优化掉,但一个没有。对于它的价值,我的编译器确实优化了两者。
PS。 CBaz baz1 = CBaz();
格式错误,因为非常量左值引用无法绑定到临时对象。
PPS。 void main()
格式错误,因为 main
必须 return int
这是直接初始化:
CFoo foo0;
这是复制初始化:
CBaz baz1 = CBaz();
由于copy elision,复制初始化在性能上等同于直接初始化,但在语义上则不同;复制初始化仍然需要一个可访问的复制构造函数。
四个析构函数打印输出中的两个来自使用 CFoo
的默认复制构造函数构造的实例。请注意,打印输出的数量取决于优化:当复制省略优化打开时,可以优化对中间情况的复制构造函数的调用,即 CFoo foo1 = CFoo()
,所以你得到三个打印输出,而不是四个。 CFoo foo2 = CFoo(foo0)
右边的一个副本没有优化掉
CBar bar1 = CBar();
不是赋值,而是使用 copy/move 构造函数的初始化。
即使省略,move/copy 构造函数也应该可以访问。
自 C++17 起,通过保证省略,规则发生了变化,并且
CBar bar1 = CBar();
不要求 move/copy 构造函数可访问,
它相当于 CBar bar1{};
.
正在学习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();
}
问题:
为什么我不能像
CFoo
那样创建CBar
的实例CBar bar1 = CBar();
?testFoo
调用 4 个析构函数。其中 3 个用于 foo0、foo1 和 foo2。 4th从哪里来?testBaz
具有相同的结构,但只调用了 3 个析构函数。CFoo
和CBaz
之间的唯一区别是CBaz
具有用户定义的复制构造函数。
- Why I can't create an instance of
CBar
asCBar bar1 = CBar();
as I did withCFoo
?
CBar
的复制构造函数被删除。因此 CBar
不可复制。因此你不能复制初始化一个 CBar
.
CFoo
是可复制的,所以没有问题。
CBar bar1 = CBar(); // Why this has anything to do with the copy constructor?
T object = other;
是复制初始化的语法。
- Where does 4th come from?
除了命名对象(变量)外,还构造了两个临时对象,CFoo()
和CFoo(foo1)
。无论出于何种原因,这些临时文件中只有一个被复制省略优化掉了。
testBaz
has the same structure, but only invokes 3 destructors.
这在某种程度上影响了优化器。我看不出为什么两个 CFoo` 临时对象都不能被优化掉,但一个没有。对于它的价值,我的编译器确实优化了两者。
PS。 CBaz baz1 = CBaz();
格式错误,因为非常量左值引用无法绑定到临时对象。
PPS。 void main()
格式错误,因为 main
必须 return int
这是直接初始化:
CFoo foo0;
这是复制初始化:
CBaz baz1 = CBaz();
由于copy elision,复制初始化在性能上等同于直接初始化,但在语义上则不同;复制初始化仍然需要一个可访问的复制构造函数。
四个析构函数打印输出中的两个来自使用 CFoo
的默认复制构造函数构造的实例。请注意,打印输出的数量取决于优化:当复制省略优化打开时,可以优化对中间情况的复制构造函数的调用,即 CFoo foo1 = CFoo()
,所以你得到三个打印输出,而不是四个。 CFoo foo2 = CFoo(foo0)
右边的一个副本没有优化掉
CBar bar1 = CBar();
不是赋值,而是使用 copy/move 构造函数的初始化。
即使省略,move/copy 构造函数也应该可以访问。
自 C++17 起,通过保证省略,规则发生了变化,并且
CBar bar1 = CBar();
不要求 move/copy 构造函数可访问,
它相当于 CBar bar1{};
.