,它用于避免复制,省略或右值引用和移动构造函数?在下面的代码中复制Elision和右值引用
std::string get(){return "...";}
void foo(std::string var){}
foo(get()); //<--- here
,它用于避免复制,省略或右值引用和移动构造函数?在下面的代码中复制Elision和右值引用
std::string get(){return "...";}
void foo(std::string var){}
foo(get()); //<--- here
std::string get(){
// this is similar to return std::string("..."), which is
// copied/moved into the return value object.
return "...";
}
RVO允许它直接构造临时字符串对象到的get()
返回值对象。
foo(get());
RVO允许它直接构建临时字符串对象(返回值对象)直接进入foo
参数对象。
这些是允许的RVO方案。如果您的编译器无法应用它们,则的将分别使用移动构造函数(如果可用)将返回值移动到返回值对象和参数对象中。在这种情况下,这并不奇怪,因为无论如何这两个临时对象都被视为右值。 (对于第一种情况,没有表达式对应于创建的临时表达式,因此处理仅用于选择将临时数据复制/移动到返回值对象时使用的构造函数)。
对于其它情况,编译器必须考虑的事情作为右值,即使他们在其他方面的左值
std::string get(){
std::string s = "...";
// this is similar to return move(s)
return s;
}
细则中指出,当它可能通过它设置的规则适用RVO(或NRVO)到左值需要实现将表达式视为rvalues并使用移动构造函数(如果可用),并且只有在找不到合适的构造函数时,才应该使用该表达式作为左值。如果程序员明确表示程序员总是需要移动而不是副本,那么程序员在这些情况下写出明确的动作可能会很遗憾。
实施例:
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;
因此,在这个例子中,我们返回"..."
的规则,我们首先创建一个右值暂时的,然后移动进入目标。对于返回返回值/参数类型表达式的情况,我们将直接将表达式复制到目标中。
实现定义,但最有可能复制省略。
类似地,当从函数返回对象值时,RVO/NRVO很可能会在移动语义之前启动。
最有可能的复制椭圆,但如果你的编译器不能应用在这种情况下,如果函数更复杂可能会发生,那么你正在寻找一个动作。移动效率非常高,所以如果没有执行ellision,我不会在这里发生恐慌。