为什么在这段代码中复制构造函数被调用了两次?
Why is the copy constructor called twice in this code snippet?
我正在研究一些东西以了解复制构造函数的工作原理。但是我无法理解为什么复制构造函数被调用两次来创建 x2
。当 createX()
的 return 值被复制到 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
有人可以帮助我解决我在这里遗漏或忽略的问题吗?
第一个副本在 createX
的 return 中
X createX() {
X x;
std::cout << "created x on the stack" << std::endl;
return x; // First copy
}
第二个是通过 createX 从临时 return 创建 x2。
X x2 = createX(); // Second copy
请注意,在 C++17 中,第二个副本被强制删除。
这里你必须记住的是,函数的 return 值是一个不同的对象。当你这样做时
return x;
您使用 x
复制初始化 return 值对象。这是您看到的第一个复制构造函数调用。那么
X x2 = createX();
使用 returned 对象复制初始化 x2
所以这是您看到的第二个副本。
需要注意的一件事是
return x;
如果可以, 将尝试将 x
移动到 return 对象中。如果你做了一个移动构造函数,你会看到这个调用。这样做的原因是因为局部对象在函数末尾超出范围,编译器将对象视为右值,并且只有在找不到有效重载时才会回退到 returning 它作为左值。
我正在研究一些东西以了解复制构造函数的工作原理。但是我无法理解为什么复制构造函数被调用两次来创建 x2
。当 createX()
的 return 值被复制到 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
有人可以帮助我解决我在这里遗漏或忽略的问题吗?
第一个副本在 createX
的 return 中X createX() {
X x;
std::cout << "created x on the stack" << std::endl;
return x; // First copy
}
第二个是通过 createX 从临时 return 创建 x2。
X x2 = createX(); // Second copy
请注意,在 C++17 中,第二个副本被强制删除。
这里你必须记住的是,函数的 return 值是一个不同的对象。当你这样做时
return x;
您使用 x
复制初始化 return 值对象。这是您看到的第一个复制构造函数调用。那么
X x2 = createX();
使用 returned 对象复制初始化 x2
所以这是您看到的第二个副本。
需要注意的一件事是
return x;
如果可以, 将尝试将 x
移动到 return 对象中。如果你做了一个移动构造函数,你会看到这个调用。这样做的原因是因为局部对象在函数末尾超出范围,编译器将对象视为右值,并且只有在找不到有效重载时才会回退到 returning 它作为左值。