从下面的代码我期望CA类可以调用以下代码
foo
a
的变量
a
变量。为什么不是这样?我的结果只是
A
虽然我在期待
ABB
因此只调用构造函数。编译器是在幕后优化还是我错过了一些C ++概念?
class CA{
public:
CA(){ std::cout << "A"; }
CA( const CA& ){ std::cout << "B"; }
CA& operator=(const CA& ){ std::cout << "C";return *this; }
};
CA foo(){
return CA();
}
int main(){
CA a = foo();
}
答案 0 :(得分:8)
编译器是在幕后优化还是我错过了一些C ++概念?
现货!它被称为复制省略。在谷歌上查找RVO和NRVO。你也应该查看三个规则。
复制elision是允许编译器执行的唯一影响可观察行为的优化。出于这个原因,您不应该在复制构造函数中放置重要的逻辑。
答案 1 :(得分:0)
C ++中至少有两种“优化”类型。
第一种是语言规范明确引入的特定优化。
第二种是编译器在“as-if”规则下进行的所有那些疯狂和不可预测的优化(即只要程序的可观察行为保持不变,编译器就可以做任何事情。)
(有些人可能会说只有第二种优化是真正的优化。)
你在这里看到的是第一种优化。执行多步复制操作时,语言规范明确总是允许编译器消除中间临时副本。
此外,C ++ 03及更高版本的语言规范更进一步:它们明确允许编译器执行“命名返回值优化”(NRVO),这实际上消除了命名(非临时) )对象。
两者都减少了程序中的复制操作次数。
即使它们改变了程序的可观察行为,也允许C ++中的这种复制消除优化,即第一类优化有时会违反对第二类的限制。在您的情况下,即使您将I / O操作插入到复制构造函数中,仍然允许编译器消除该构造函数的调用。
您发布的代码不需要NRVO。一个好的C ++ 98编译器应该能够产生你观察到的结果。如果你想看看你的编译器在这种情况下是否做了NRVO,你可能想尝试这个
CA foo(){
Ca ca;
return ca;
}