C++ 复制省略和右值引用

C++ 复制省略和右值引用,c++,c++11,C++,C++11,在下面的代码中,使用什么来避免复制、省略或右值引用和移动构造函数 std::string get(){return "...";} void foo(std::string var){} foo( get() ); //<--- here std::string get(){return“…”;} void foo(std::string var){} foo(get())// 已定义实现,但很可能是复制省略 类似地,当从函数返回对象值时,RVO/NRVO很可能在移动语义之前生效 s

在下面的代码中,使用什么来避免复制、省略或右值引用和移动构造函数

std::string get(){return "...";}

void foo(std::string var){}

foo( get() ); //<--- here
std::string get(){return“…”;}
void foo(std::string var){}

foo(get())// 已定义实现,但很可能是复制省略

类似地,当从函数返回对象值时,RVO/NRVO很可能在移动语义之前生效

std::string get(){
    // this is similar to return std::string("..."), which is
    // copied/moved into the return value object.
    return "...";
}
RVO允许它将临时字符串对象直接构造到
get()
的返回值对象中

RVO允许它直接将临时字符串对象(返回值对象)构造到
foo
的参数对象中

这些是允许的RVO场景。如果编译器无法应用它们,则必须使用移动构造函数(如果可用)将返回值分别移动到返回值对象和参数对象中。在这种情况下,这并不奇怪,因为两个临时对象都被视为或被视为右值。(对于第一个场景,没有表达式对应于创建的临时对象,因此处理仅用于选择用于将临时对象复制/移动到返回值对象中的构造函数)

对于其他情况,编译器必须将事物视为rValk,即使它们是LValue/P>

std::string get(){
    std::string s = "...";
    // this is similar to return move(s)
    return s;
}
该规范指出,当它可能根据规定的规则将RVO(或NRVO)应用于左值时,需要实现将表达式视为右值并使用移动构造函数(如果可用),并且只有在找不到合适的构造函数时,才应将表达式作为左值使用。对于程序员来说,在这种情况下编写显式的移动是很遗憾的,因为很明显,程序员总是希望移动而不是复制

例如:

struct A { A(); A(A&); };
struct B { B(); B(B&&); };

A f() { A a; return a; }
B f() { B b; return b; }
对于第一种情况,它将
a
作为右值,但找不到接受此右值的构造函数(
a&
无法绑定到右值)。因此,它再次将
a
视为它是什么(左值)。对于第二个,它将
b
作为右值,并使
b(b&&)
获取该右值并移动它。如果它将
b
作为左值(它是什么),那么复制初始化将失败,因为
b
没有隐式声明复制构造函数


请注意,返回和参数传递使用复制初始化规则,这意味着

u -> T (where u's type is different from T) =>
  T rvalue_tmp = u;
  T target(rvalue_tmp);

t -> T (where t's type is T) =>
  T target = t;

因此,在返回
“…”
的示例中,我们首先创建一个临时右值,然后将其移动到目标中。对于返回返回值/参数类型的表达式的情况,我们将直接将该表达式移动/复制到目标中

最有可能是复制省略,但如果编译器无法在这种情况下应用(如果函数更复杂,可能会发生这种情况),那么您正在考虑移动。移动非常有效,所以如果不执行省略,我不会在这里惊慌失措

u -> T (where u's type is different from T) =>
  T rvalue_tmp = u;
  T target(rvalue_tmp);

t -> T (where t's type is T) =>
  T target = t;