在函数重载中将rvalue引用实现为参数

Alb*_*ola 5 c++ c++11 c++17

我已经问过代码审查和软件工程,但主题不适合网站,所以我在这里要求希望这不是基于意见的.我是一个"老派"C++开发人员(我已经在C++ 2003上停了下来),但现在我读了几本关于现代C++ 11/17的书,我正在重写我的一些库.

我做的第一件事是在需要的地方添加移动构造函数/赋值运算符(=已经有析构函数+复制构造函数和复制赋值的类).基本上我使用规则.

我的大部分功能都被声明为

func(const std::string& s);
Run Code Online (Sandbox Code Playgroud)

哪种方法是传递避免副本的引用.顺便说一句,还有新的移动语义,而且我的书/网上找不到一些东西.这段代码:

void fun(std::string& x) {
    x.append(" world"); 
    std::cout << x;
}

int main()
{
    std::string s{"Hello "};
    fun(s);
}
Run Code Online (Sandbox Code Playgroud)

也可以写成:

void fun(std::string&& x) {
    x.append(" world"); 
    std::cout << x;
}

int main()
{
    std::string s{"Hello "};
    fun(std::move(s));
    //or fun("Hello ");
    // or fun(std::string {"Hello" });
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:我何时应该声明接受作为右值参考的参数的函数?


我理解构造函数和赋值运算符的&& semantic的用法,但不是函数.在上面的例子中(第一个函数)我有一个当然std::string& x不能被调用fun("Hello ");的因为我应该将类型视为delcare const std::string& x.但现在const不允许我改变字符串!

是的,我可以使用const转换,但我很少进行强制转换(如果是这样的话,它们就是动态转换).&&的力量是我避免复制,我不必做类似的事情

std::string x = "...";
fun(x); //void fun(std::string& x) {}
Run Code Online (Sandbox Code Playgroud)

而且我可以确定将被移动的临时值.我应该在可能的情况下用rvalue引用声明函数吗?

我有一个我用现代C++ 17重写的库,我有以下功能:

//only const-ref
Type1 func(const type2& x);
Type3 function(const type4& x);
Run Code Online (Sandbox Code Playgroud)

我在问是否值得重写所有这些

//const-ref AND rvalue reference
Type1 func(const type2& x);
Type3 function(const type4& x);

Type1 func(type2&& x);
Type3 function(type4&& x);
Run Code Online (Sandbox Code Playgroud)

我不想创建太多可能无用的重载但是如果我的库的用户想要使用移动操作,我应该创建&& param类型.当然我不是为原始类型(int,double,char ...)而是为了容器或类.你有什么建议?

我不确定后一种情况(两种版本)是否有用.

lub*_*bgr 4

让我评论一下您的问题和示例中的四个场景。

  • std::string_view使用值传递应该替换const std::string&参数,并且只要您可以保证安全使用的必要先决条件std::string_view(生命周期,指针不会改变),它就是开始现代化函数签名的一个很好的选择。
  • const T&与已知使用场景的比较T&&T不受模板类型推导的影响)。附加到给定的可修改字符串的函数只有在调用代码不需要调用后的结果时才void fun有意义。void fun(std::string&&)在这种情况下,右值引用签名很好地记录了这种期望,并且是可行的方法。但以我的经验来看,这些案例相当罕见。
  • const T&与未知使用场景的对比T&&(再次强调,没有类型推导)。这里一个很好的参考是std::vector::push_back,它对于右值和左值引用都是重载的。与 move-construction a 相比,push_back 操作被认为是便宜的T,这就是重载有意义的原因。当假设函数比此类移动构造更昂贵时,按值传递参数是一种有意义的简化(另请参阅 EMC++ 中的第 41 条)。
  • const T&T&&与发生类型推导时相比。在这里,尽可能使用通用引用,并且std::forward参数不能是 const 限定的。如果它们没有在函数体中修改,请使用const T&.