关于复制构造函数的一个棘手问题
A tricky question regarding Copy Constructor
我的困惑在于第 Cube c = a;
行。我认为它应该同时调用默认构造函数和复制构造函数,但实际上它只调用复制构造函数。
难道 Cube c
和 Cube a
一样,不是一个应该调用默认构造函数的新对象吗?
class Cube
{
public:
int length_;
Cube(){
length_ = 1;
cout<< "Default Constr"<< endl;
}
Cube(const Cube & obj){
length_ = obj.length_;
cout<< "Copy Constr"<< endl;
}
};
Cube foo(){
Cube c;
return c;
}
int main() {
Cube a; //invoke default constructor only
Cube c = a; //invoke copy constructor only
return 0;
}
调用默认构造函数。
它用于初始化对象。
然后复制构造函数用于将新对象的状态设置为与初始对象相同。
当你写:
Cube c = a;
这实际上不是作业,而是 copy-initialization。
在你的情况下,这与你写的一样:
Cube c(a);
只调用复制构造函数。
请记住,一个对象只构造一次,因此只有一个构造函数。
正如其他人所指出的,您这里的是复制初始化,因此无法使用默认构造函数。
有一种稍微不同的情况,其中复制初始化可以(至少理论上)涉及一个额外的步骤。考虑这样的代码:
class foo {
public:
foo(int) {}
};
int main() {
foo f = 1;
}
在这种情况下,(至少在 C++17 之前)理论上应该涉及两个独立的构造函数。首先,构造一个临时对象,用 1
初始化,然后调用复制构造函数从该临时对象初始化 f
。
在这种情况下,大多数编译器将生成直接从 q
初始化 f
的代码,因此它等同于 foo f{1};
。编译器仍然需要尊重需要副本的事实,因此如果删除复制构造函数,编译将失败:
class foo {
foo(foo const &)= delete;
public:
foo(int) {}
};
int main() {
foo f = 1;
}
结果(使用 gcc):
trash9.cpp: In function 'int main()':
trash9.cpp:8:17: error: use of deleted function 'foo::foo(const foo&)'
foo f = 1;
^
trash9.cpp:2:9: note: declared here
foo(foo const &) = delete;
^~~
trash9.cpp:4:9: note: after user-defined conversion: 'foo::foo(int)'
foo(int) {}
^~~
但是从 C++17 开始的规则的变化意味着现在即使这样也是允许的(所以如果我在上面的编译中添加 -std=c++17
,它就会成功)。
我的困惑在于第 Cube c = a;
行。我认为它应该同时调用默认构造函数和复制构造函数,但实际上它只调用复制构造函数。
难道 Cube c
和 Cube a
一样,不是一个应该调用默认构造函数的新对象吗?
class Cube
{
public:
int length_;
Cube(){
length_ = 1;
cout<< "Default Constr"<< endl;
}
Cube(const Cube & obj){
length_ = obj.length_;
cout<< "Copy Constr"<< endl;
}
};
Cube foo(){
Cube c;
return c;
}
int main() {
Cube a; //invoke default constructor only
Cube c = a; //invoke copy constructor only
return 0;
}
调用默认构造函数。 它用于初始化对象。 然后复制构造函数用于将新对象的状态设置为与初始对象相同。
当你写:
Cube c = a;
这实际上不是作业,而是 copy-initialization。
在你的情况下,这与你写的一样:
Cube c(a);
只调用复制构造函数。
请记住,一个对象只构造一次,因此只有一个构造函数。
正如其他人所指出的,您这里的是复制初始化,因此无法使用默认构造函数。
有一种稍微不同的情况,其中复制初始化可以(至少理论上)涉及一个额外的步骤。考虑这样的代码:
class foo {
public:
foo(int) {}
};
int main() {
foo f = 1;
}
在这种情况下,(至少在 C++17 之前)理论上应该涉及两个独立的构造函数。首先,构造一个临时对象,用 1
初始化,然后调用复制构造函数从该临时对象初始化 f
。
在这种情况下,大多数编译器将生成直接从 q
初始化 f
的代码,因此它等同于 foo f{1};
。编译器仍然需要尊重需要副本的事实,因此如果删除复制构造函数,编译将失败:
class foo {
foo(foo const &)= delete;
public:
foo(int) {}
};
int main() {
foo f = 1;
}
结果(使用 gcc):
trash9.cpp: In function 'int main()':
trash9.cpp:8:17: error: use of deleted function 'foo::foo(const foo&)'
foo f = 1;
^
trash9.cpp:2:9: note: declared here
foo(foo const &) = delete;
^~~
trash9.cpp:4:9: note: after user-defined conversion: 'foo::foo(int)'
foo(int) {}
^~~
但是从 C++17 开始的规则的变化意味着现在即使这样也是允许的(所以如果我在上面的编译中添加 -std=c++17
,它就会成功)。