12.8复制和移动类对象[class.copy]§31和§32说:
在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象(函数或catch子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.
因此我们可以写:
unique_ptr<int> make_answer()
{
unique_ptr<int> result(new int(42));
return result; // lvalue is implicitly treated as rvalue
}
Run Code Online (Sandbox Code Playgroud)
但是,我注意到g ++ 4.6.3也接受不是名称的左值,例如:
return (result);
return *&result;
return true ? result : result;
Run Code Online (Sandbox Code Playgroud)
相比之下,return rand() ? result : result;不起作用.编译器的优化器是否会干扰语言语义?当我解释标准时,return (result);不应该编译,因为(result)它不是名称,而是带括号的表达式.我是对还是错?
请考虑以下示例:
#include <cstdio>
class object
{
public:
object()
{
printf("constructor\n");
}
object(const object &)
{
printf("copy constructor\n");
}
object(object &&)
{
printf("move constructor\n");
}
};
static object create_object()
{
object a;
object b;
volatile int i = 1;
// With #if 0, object's copy constructor is called; otherwise, its move constructor.
#if 0
if (i)
return b; // moves because of the copy elision rules
else
return a; // moves because of the copy elision rules
#else
// Seems equivalent …Run Code Online (Sandbox Code Playgroud) 看完这个问题后.我创建了这个小小的测试:
class A{
public:
A(){}
A(const A&){printf("copy\n");}
A(A&&){printf("move\n");}
static A f(){
A a;
return a;}
static A g(){
A a;
return (a);}//could be return *&a; too.
static A h(){
A a;
return true?a:a;}
};
Run Code Online (Sandbox Code Playgroud)
结果是(没有RVO和NRVO):
据我所知,用于决定是否使用复制或移动的规则在12.8.32中描述:
这是指12.8.31的规则:(我只显示相关部分)
按照这些规则,我理解f和h会发生什么:
怎么样?
对我来说,它看起来很像h.我正在返回一个表达式,它不是自动对象的名称,因此我认为它会被复制但是它被移动了.这里发生了什么?
在VS2013上编译的以下代码从不调用std :: string的移动构造函数(通过设置断点检查,而是调用const ref复制构造函数.
#include <iostream>
#include <string>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
struct foo
{
foo(std::string& str1, std::string& str2) : _str1(str1), _str2(str2) {}
~foo() { std::cout << "Either \"" << _str1 << "\" or \"" << _str2 << "\" was returned." << std::endl; }
std::string& _str1;
std::string& _str2;
};
std::string foobar()
{
std::string str1("Hello, World!");
std::string str2("Goodbye, cruel World.");
foo f(str1, str2);
srand(time(NULL));
return (rand() % 2) ? str1 : str2;
}
int …Run Code Online (Sandbox Code Playgroud)