C++三元表达式为何触发拷贝?true分支执行仍出现拷贝
三元表达式中意外触发拷贝构造的原因分析
问题代码
#include <iostream> struct X { X() = default; X(int value) : value(value) {} X(const X &x) : value(x.value) { std::cout << "copy" << std::endl; } int value = 0; }; struct Z { Z(const X &x) : x(x) {} const X &get_x() const {return x;} X x; }; X get_x(const Z &z) { return z.get_x(); } int main() { X x1(2); Z z1(x1); std::cout << "----" << std::endl; const X &x2 = (true) ? z1.get_x() : get_x(z1); // (1) std::cout << "----" << std::endl; const X &x3 = (true) ? z1.get_x() : z1.get_x(); // (2) }
输出结果
copy ---- copy ----
原因解析
核心在于C++三元运算符的结果类型统一规则:
- 代码中的(2)行,两个分支返回的都是
const X&类型,因此三元表达式的结果类型直接是const X&,可以直接绑定到x3,不会触发拷贝。 - 代码中的(1)行,true分支返回
const X&,但false分支返回的是X(值类型)。编译器在编译阶段必须确定三元表达式的唯一结果类型,此时会将引用类型转换为值类型:它会把true分支引用的z1.x拷贝生成一个临时X对象,作为三元表达式的结果,再将x2绑定到这个临时对象。
这个类型转换逻辑是编译期决定的,和运行时实际执行哪个分支无关。哪怕条件是true,编译器依然会生成拷贝代码来满足类型统一要求,因此触发了拷贝构造函数。
另外,开头的第一个copy是创建Z对象z1时,其成员x从x1拷贝初始化导致的,属于预期行为。
内容的提问来源于stack exchange,提问作者JakeTuero
相关产品推荐
相关产品推荐

