我正在研究一些事情,以了解复制构造函数的工作方式。但是我无法理解为什么在创建x2
时两次调用了复制构造函数。我以为将createX()
的返回值复制到x2
时会调用一次。
我还查看了一些有关SO的相关问题,但据我所知,我找不到与我在此处询问的相同的简单情况。
顺便说一句,我正在使用-fno-elide-constructors
进行编译,以了解未进行优化的情况。
#include <iostream>
struct X {
int i{2};
X() {
std::cout << "default constructor called" << std::endl;
}
X(const X& other) {
std::cout << "copy constructor called" << std::endl;
}
};
X createX() {
X x;
std::cout << "created x on the stack" << std::endl;
return x;
}
int main() {
X x1;
std::cout << "created x1" << std::endl;
std::cout << "x1: " << x1.i << std::endl << std::endl;
X x2 = createX();
std::cout << "created x2" << std::endl;
std::cout << "x2: " << x2.i << std::endl;
return 0;
}
这是输出:
default constructor called
created x1
x1: 2
default constructor called
created x on the stack
copy constructor called
copy constructor called
created x2
x2: 2
有人可以帮我我在这里遗失或忽略的东西吗?
答案 0 :(得分:19)
您在这里必须记住的是,函数的返回值是一个不同的对象。当你做
return x;
您复制使用x
初始化返回值对象。这是您看到的第一个副本构造函数调用。然后
X x2 = createX();
使用返回的对象复制初始化x2
,这是您看到的第二个副本。
要注意的一件事是
return x;
将尝试将x
移入返回对象。如果您创建了一个move构造函数,您将看到此调用。这样做的原因是,由于局部对象在函数末尾超出范围,因此编译器将对象视为右值,并且只有在找不到有效的重载时,它才退回到以左值返回。 / p>
答案 1 :(得分:12)
第一个副本是createX的返回
X createX() {
X x;
std::cout << "created x on the stack" << std::endl;
return x; // First copy
}
第二个是从createX的临时返回中创建x2。
X x2 = createX(); // Second copy
请注意,在C ++ 17中,第二个副本被强制删除。