ein*_*ica 3 c++ stdstring compiler-optimization copy-elision stdmove
(这个问题的灵感来自Nicolai Josuttis的CppCon 2017演讲.)
考虑以下源文件(对于对象,而不是完整的程序):
#include <string>
class C {
std::string s_;
public:
C(std::string s) : s_(s) { };
void bar();
};
void foo() {
std::string hello { "The quick brown fox jumped over the lazy dog" };
C c { hello };
c.bar();
}
Run Code Online (Sandbox Code Playgroud)
即使使用-O2(甚至使用-O3),似乎字符串构造函数被调用三次.具体而言,s构造,仅用于构造s_,然后被破坏.我的问题:
s_从ctor的参数构造,而不是构造s?s_从s,看到后者是如何闲置?s构造正确,编译器不能避免构造hello,看看它没有其他用途吗?或者至少离开它?在假设的情况下,我确定你要求的大部分内容都可以完成,假设你去链接时间而你bar做空并且永远不会覆盖新的任何地方.
但是,根据假设,你的程序是一个空程序,它没有可观察到的影响.
编译器不允许移动构建体s_从s抽象机的规则下.如果你想要它被移动构造,std::move它.
左值可以被视为右值的情况是有限且具体的并涉及return x;陈述.这不是一个return x;声明.
所以你的代码必须复制s到s_.很可能它也应该产生警告作为实施质量问题.
编译器不允许s进入s_.已经有一些c ++ 20提案允许更加激进的省略规则.
但截至目前,elision只能在假设,prvalues或return x;声明下使用.如果消除确实非常难以用分配这么复杂的东西来证明,大多数编译器都不会尝试.并且在目标文件生成中是不可能的,因为有人可以替换全局分配器.
想象一下全局分配器覆盖,它打印出完成了多少分配.然后使用那些"从未使用过"的对象,因为他们应该打印出他们所做的分配.
或者是exit在2次分配后调用的全局分配器.由此产生的抽吸机应该永远不会打电话bar(); 如果我们消除你的额外对象,程序就不会像标准要求那样行事.