Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 右值引用与类设计_C++_Interface_C++11_Rvalue Reference - Fatal编程技术网

C++ 右值引用与类设计

C++ 右值引用与类设计,c++,interface,c++11,rvalue-reference,C++,Interface,C++11,Rvalue Reference,我试图评估右值引用如何影响类的设计。假设我有一个如下所示的现有类 class X { string internal; public: void set_data(const char* s) { internal = s; } .. .. .. //other stuff }; 此类由另一个模块使用,如下所示: //another module { string configvalue; X x; //read config

我试图评估右值引用如何影响类的设计。假设我有一个如下所示的现有类

class X
{
   string internal;

public:
   void set_data(const char* s)
   {
      internal = s;
   }
..
..
..
//other stuff

};
此类由另一个模块使用,如下所示:

//another module
{

    string configvalue;
    X x;

    //read configvalue from a file and call set 

    ...
    x.set_data(configvalue.c_str());

    //use x to do some magic
    ..
    ...


}
有了右值引用,提供另一个这样的成员函数会更好吗

class X
{
...
...
....
 void set_data(string s)
 {
     internal = std::move(s);
 }
};
这将允许此类的客户端使用移动语义,并防止每次使用一组分配/复制操作。这是一个高度捏造的例子,但相同的原则是否适用于所有类设计,而不打破“最小接口”范式


任何人对此问题的见解都非常感谢?

我认为没有理由将
无效集数据(const char*s)
无效集数据(字符串)
作为接口的一部分。这将产生歧义,并容易产生副作用。此外,在调用
set\u data(string s)
时,仍按值传递参数。相反,我建议定义以下两个函数:

void set_data(const string &s);
void set_data(string &&s);
这样,您可以有两种实现,第一种实现将深度复制字符串,第二种实现可以窃取字符串的内部,因为它是
rvalue
(请确保将其保持在已定义状态,以便析构函数能够毫无问题地销毁它-有关详细信息,请参阅)

第二个版本将在
rvalue
string
参数上自动调用,或者如果参数被强制为
rvalue
,例如通过
std::move


如果您还想拥有一个按值选项,您可以使用此API的
rvalue
版本,并结合字符串复制构造函数:
set_data(string(str))
是的,按照您的建议添加
字符串
重载是一个好主意。即使没有右值引用,这样的重载也是个好主意。否则,给定一个
std::string s
,要使用它,必须:

x.set_data(s.c_str());
鉴于

x.set_data(s);
对于
X
的客户端来说,它更直观(甚至更高效)

作为另一个选项,您可以添加以下两个重载:

void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}
这大致相当于您正确建议的单个重载。双过载解决方案的性能优势很小。当传递的参数是xvalue(使用
std::move
强制转换的左值)时,单个重载解决方案将需要额外的
string
move构造。但是
std::string
的move构造函数应该非常快,所以这应该不是什么大问题。我只是本着充分披露的精神提及此事

如果
set\u data
有多个参数,则“按值”方法将更具吸引力。例如,考虑需要传入两个<代码>字符串< /代码>的情况。你的选择是:

解决方案1

void set_data(string s1, string s2);
解决方案2

void set_data(const string&  s1, const string&  s2);
void set_data(      string&& s1, const string&  s2);
void set_data(const string&  s1,       string&& s2);
void set_data(      string&& s1,       string&& s2);
正如您很快看到的,解决方案2随参数数量的增加而伸缩性很差

最后,在任何情况下都不应尝试将两种解决方案应用于同一类型:

不要这样做

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}
void set_data(string&& s)      {internal = std::move(s);}
这组重载将是不明确的。正如在C++03中一样,以下两个重载是不明确的:

void set_data(string s)        {internal = std::move(s);}
void set_data(const string& s) {internal = s;}

千万不要用引用的值重载,不管是左值引用还是右值引用。

@HowardHinnant否。你有吗?是的。当我实现前两个
set_data
并使用右值
字符串调用时,我的编译器抱怨有歧义。当我添加第三个
set\u数据
重载时,当使用左值
字符串
调用时,我也会得到一个歧义。a,是-因为by value。它应该被移除,如果需要的话,可以通过其他两种方法和某种克隆方法获得相同的结果,例如example@HowardHinnanta,是的,你是对的——因为按价值计算。它应该被移除,如果需要的话,可以通过其他两种方法和某种克隆方法获得相同的结果。我已经编辑了答案。
void set_data(const string&s){internal=s;}void set_data(string&s){internal=std::move(s);}
,何时第一次调用,何时第二次调用?第一个版本更喜欢绑定到左值。。。第二个版本更喜欢绑定到包含在
std::move
中的右值和左值。关于多个参数的传递-是的,它的伸缩性很差-但这不应该是选择“按值”方法的原因。通过将参数存储在一个单独的配置对象中(该对象将通过引用传递给重载函数),可以很容易地解决这个问题(并且可能是出于设计考虑),从而将问题简化为具有单个参数的原始问题