是否应该从现在开始声明所有C++函数的rvalue?

ste*_*t99 8 c++ c++11

我为什么要或不应该创建我的所有函数和成员函数来取一个带有a的rvalue版本lvalue?你总是可以转发lvalue到右转,对吧?我甚至可以拥有const rvalue,为什么这是一个坏主意或好主意呢?

我在代码中的意思如下.该"&&" rvalue引用允许用户使用临时对象,并且仍然可以lvalue通过简单的转发使用.所以考虑到这一点,我为什么要提供print_string(string& str)(lvalue参考)c ++ 11中的任何函数(除了const参考,因为rvalue有好的)?

#include <iostream>
#include <string>
#include <utility>

using namespace std;


void print_string(string&& str)
{
    str += "!!!";
    cout << str << endl;
}
void print_string2(string& str)
{
    str += "???";
    cout << str << endl;
}

int main(int argc, char* argv[])
{

    print_string("hi there");  // works
    print_string(string("hi again")); // works
    string lvalue("lvalue");
    print_string(forward<string>(lvalue)); // works as expected
    //print_string(lvalue);  // compile error

    //print_string2("hi there"); // comile error
    //print_string2(string("hi again")); // compile error
    print_string2(lvalue);


    char a;
    cin >> a;
}
Run Code Online (Sandbox Code Playgroud)

产量

嗨,您好!!!
你好,我们又见面了!!!
左值!
左值!!! ???

void print_string(string&& str)提供了一个更灵活的用例void print_string2(string& str),为什么我们不应该一直使用rvalue参数呢?

dyp*_*dyp 6

与C++的许多功能一样,有一个如何使用左值和右值引用的约定.

为惯例另一示例是运营商,尤其是==!=.您可以重载它们以返回doubles,并复制文件以进行比较.但按照惯例,它们返回bool并且只比较左右操作数而不进行修改.


rvalue引用的约定是它们引用资源可能被"窃取"的对象:

  • 左值引用意味着该对象归其他人所有
  • 右值引用意味着我们可以从对象中窃取资源

引入了Rvalue引用以支持移动语义,即资源所有权的转移.移动语义通常意味着可以移动绑定到右值引用的对象.从传统上移动的对象被假定为处于有效但未知的状态.例如:

// returns a string that equals i appended to p
string join(string&& p, int i); // string&& means: I do something to p. Or not.

// append i to p
void append(string& p, int i);


string my_string = "hello, world."; // length is 13

append(my_string, 42); // I know what state my_string is specified to be in now
my_string[12] = "!"; // guaranteed to work

string result = join( std::move(my_string), 42 );
// what state is my_string now in?
char c = my_string[1]; // is this still guaranteed to work?


string const cresult = join("hello, number ", 5);
// fine, I don't care what state the temporary is in -- it's already destroyed
Run Code Online (Sandbox Code Playgroud)

人们可以想到如下定义:

string join(string&& p, int i)
{  return std::move(p) + std::to_string(i);  }

void append(string& p, int i)
{  p += std::to_string(i);  }
Run Code Online (Sandbox Code Playgroud)

这个定义join确实从中窃取资源p,而标准实际上并没有指定p操作后的状态std::move(p) + std::to_int(i)(这会创建一个从中窃取资源的临时状态p).

对于这个简单的例子,您仍然可以使用

string result = "hello ";
result = join(std::move(result), 42);
Run Code Online (Sandbox Code Playgroud)

"替换" append.但是移动也可能很昂贵(它们总是复制某些东西),并且这种技术不能轻易替换多个左值参考参数.

在我看来,你应该在函数的名称中指出它是否需要左值引用并修改参数.我当然不希望命名的函数print_string2修改我传入的字符串.


恕我直言,移动对象处于一个有效但未指定状态的惯例,应该阻止你在任何地方使用右值引用.

此外,与使用就地操作相比,使用太多移动可能会对性能产生轻微影响join.


ste*_*t99 5

各种stackexchange问​​题已帮助我回答了自己的问题。

我向前走,感到困惑。这个答案很有帮助(我通常可以/总是使用std :: forward而不是std :: move吗?)您可以r / forward / move / g,但我的问题仍然相同。请务必直接阅读Scott Meyer对这个问题的回答:http : //scottmeyers.blogspot.co.uk/2012/11/on-superfluousness-of-stdmove.html

那是个好主意吗?好了,这些帖子帮助我弄清楚了:在C ++ 11中,按值传递是否是合理的默认值?

是否应该将C ++ 11中的所有/大多数设置器函数编写为接受通用引用的函数模板?

我是否应该一直使用`sink`构造函数或setter参数?

  • 如果不链接人们必须阅读的一堆东西,您是否可以总结在答案本身中学到的知识? (2认同)