C++ 所有C++;函数从现在开始声明为右值?
为什么我应该或不应该创建所有函数和成员函数来接受C++ 所有C++;函数从现在开始声明为右值?,c++,c++11,C++,C++11,为什么我应该或不应该创建所有函数和成员函数来接受rvalue,而忽略接受lvalue的版本?您总是可以将左值转发到右值,对吗?我甚至可以使用常量值,为什么这是一个坏主意,还是一个好主意 我在代码中的意思如下。“&&&“rvalue引用允许用户使用临时值,并且仍然可以通过简单的转发使用lvalue。因此,考虑到这一点,我为什么要在c++11中提供任何函数的print_string(string&str)(levaluereference)(除了constreference之外,因为rvalue没有
rvalue
,而忽略接受lvalue
的版本?您总是可以将左值
转发到右值,对吗?我甚至可以使用常量值
,为什么这是一个坏主意,还是一个好主意
我在代码中的意思如下。“&&&“rvalue
引用允许用户使用临时值,并且仍然可以通过简单的转发使用lvalue
。因此,考虑到这一点,我为什么要在c++11中提供任何函数的print_string(string&str)
(levalue
reference)(除了const
reference之外,因为rvalue
没有问题)
#包括
#包括
#包括
使用名称空间std;
无效打印字符串(字符串和字符串(&str)
{
str+=“!!!”;
Cuth和C++的许多特性一样,有一个关于如何使用LValk和RValk引用的约定。
约定的另一个示例是运算符,尤其是
=
和!=
。您可以重载它们以返回双精度
s,并复制文件进行比较。但是按照约定,它们返回bool
,并且只比较左右操作数而不进行修改
右值引用的约定是,它们引用的对象的资源可能被“窃取”:
- 左值引用意味着对象为其他人所有
- 右值引用意味着我们可以从对象中窃取资源
引入右值引用是为了支持移动语义,即资源所有权的转移。移动语义通常意味着绑定到右值引用的对象可以从中移动。从对象中移动通常被假定为处于有效但未知的状态。例如:
// 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
人们可以想到这样的定义:
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); }
这个join
的定义确实从p
中窃取了资源,标准也确实没有指定操作std::move(p)+std::to_int(i)
后p
的状态(它创建了一个从p
中窃取资源的临时文件)
对于这个简单的示例,您仍然可以使用
string result = "hello ";
result = join(std::move(result), 42);
“替换”append
。但是移动也可能很昂贵(它们总是复制某些内容),并且多个左值引用参数不容易被这种技术替换
注意:在我看来,当函数接受左值引用并修改参数时,应该在函数名中指明。我当然不希望名为print\u string2
的函数修改传入的字符串
IMHO,按照惯例,moved from对象处于有效但未指定的状态,这将阻止您在任何地方使用右值引用
此外,当使用过多的移动而不是就地操作时,可能会对性能产生轻微影响。join
各种stackexchange问题帮助我回答了自己的问题
我对前进和前进感到困惑。这个答案有帮助()你可以r/forward/move/g,我的问题仍然是一样的。请务必直接阅读Scott Meyer对这个问题的回答:
这是个好主意吗?这些帖子帮我弄明白了:
及
及
打印字符串2
是一种糟糕的设计。它会修改字符串。例如,有人可能会写:
string s{"hello"};
print_string2(s); // print the string
foo(s); // work on the string - oops, it has junk punctuation on it now.
如果函数修改调用方的字符串,则不应调用它
所以你是对的,string&
比string&
好,但这两个选项都是次优的
相反,此函数只能按值接受字符串:
void print_string2(string s)
然后,如果您使用右值(包括xvalues)调用它,参数将移动到s
,如果您使用左值调用它,则会生成一个副本,这是理想的行为
如果函数不需要修改字符串作为其处理的一部分,则应传递常量引用,该引用可以绑定到右值和左值:
void print_string(const string &s)
{
在您的示例中,这是最好的选择,因为在打印左值时不需要复制字符串。正文将是:
cout << str << "???" << endl;
cout No!在有意义的地方使用右值(应用std::move
或提供合理的std::swap
实现),否则,像往常一样坚持使用const&
或值传递的参数。您可能会注意到,考虑到新的c++11功能,三的规则可能会变成五的规则。作为一个严格的规则,不应用足够的思想,做一些事情最多是危险的。为正确的工作使用正确的工具。使用r值参考很明显,所管理的资源是可移动的,而使用const l-value ref则说明了这一点。严格的规则:不要停止思考。这会让无数呼叫站点使用std::foward
/std::move
,这是愚蠢的。我仍然不明白为什么在所有新功能中,r-value reference是一道闪电这充其量只是一个小功能,是专门为解决两个特定问题而设计的。C++11的99%的新功能更值得了解和使用。如果不链接人们必须通读的内容,你能总结一下你在答案中学到的东西吗?
cout << str << "???" << endl;