考虑如下代码:
struct S { public: S(int i) { m = i; } ~S() { std::cout << "~S() called \n"; } int m; }; void fun(S s) { std::cout << "fun called \n"; } int main() { fun(S(1)); }
S(1)构造了一次,是个无名的临时对象(暂且给它取名为tmp),然后传递给fun函数,s是另一个局部对象。因此程序应打印两次~S() called。(实测vs2015打印2次,gcc和clang中只打印一次)
C++17开始,S(1)这个纯右值不一定要物化为tmp,意思是在这个程序中,根本就没有创建tmp对象。因此,在C++17支持的编译器中,只打印一次~S() called.
这绝非编译器厂家自由选择的优化技术,编译器的优化技术认为,S(1)和fun(S s)中的s是一回事,就直接在s的构造上做文章。(见《Inside C++ Model》)
C++17 强制要求纯右值prvalue只是初始化语义,意思是prvalue只能帮助其它对象初始化,自己是不能轻易物化的。这里,fun(S(1))就没有发生temporary materialization。那么,何时会发生呢?例如:
int k = fun().m;
这样子,fun()返回的纯右值不物化也不成了,因为要访问它的对象m。
其它物化条件,见 http://en.cppreference.com/w/cpp/language/implicit_conversion#Temporary_materialization