C++11 按值传递和按右值传递引用的重载
我有两个子程序重载,它接受一个类型的参数,该参数占用了数兆的动态内存,并且有一个移动构造函数和赋值运算符:C++11 按值传递和按右值传递引用的重载,c++11,parameter-passing,move-semantics,rvalue-reference,C++11,Parameter Passing,Move Semantics,Rvalue Reference,我有两个子程序重载,它接受一个类型的参数,该参数占用了数兆的动态内存,并且有一个移动构造函数和赋值运算符: // Version intended for use when we the caller has // deliberately passed an rvalue reference using std::move void MyClass::setParameter(MyMoveableType &&newParameter) { m_theLocalPar
// Version intended for use when we the caller has
// deliberately passed an rvalue reference using std::move
void MyClass::setParameter(MyMoveableType &&newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
// Version intended for use when the caller has passed
// some other type of value which shouldn't be moved
void MyClass::setParameter(MyMoveableType newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
很明显,第一个重载将newParameter的内容从子例程调用newParameter对象的链的上游移动,而第二个重载将创建newParameter的全新副本(或在适当的情况下调用复制省略以避免这样做,例如参数实际上是函数的返回值),然后将副本移动到本地数据成员中,从而避免进一步的副本
但是,如果我尝试使用第一个重载将对象移动到类中:
{
MyClass theDestination;
MyMoveableType theObject
...
// ...Various actions which populate theObject...
...
TheDestination.setParameter(std::move(theObject));
...
}
…然后,在我尝试过的每个编译器上,我都会遇到如下错误:
call to member function 'setParameter' is ambiguous
现在我可以看到,将右值引用传递给第二个重载实际上是完全合法的,而且如果我没有提供第一个重载,我希望编译器在不发出警告的情况下会这样做。即使如此,我希望编译器完全清楚这段代码的意图,因此我希望它会这样做选择第二个重载作为最佳匹配
我可以通过重新定义第二个构造函数以获取const引用并删除std::move来消除这个错误(尽管这样做不会出错)
保留它;编译器会忽略它)。这可以正常工作,但我会失去利用复制省略的机会。这可能是
对于该特定应用程序而言,在性能方面具有重要意义;讨论的对象是以30秒的速度传输的高分辨率视频帧
每秒帧数
在这种情况下,我能做些什么来消除重载的歧义,从而使我的例程同时有一个pass-by-value和pass-by-rvalue引用版本
很明显,第一个重载将newParameter的内容从子程序调用newParameter对象的链的上游移动,而第二个重载将创建一个全新的副本
这并不是你真正要做的。你有两个明智的选择:
接近A
您只需编写值重载,然后无论如何都要从中移动—这意味着您将始终支付构造函数的代价,要么移动,要么复制
方法B
您可以为(const T&)
和(T&&)
编写重载。这样,您可以在第一个文件中复制,并使用完美转发跳过第二个文件中的移动
我建议默认使用方法A,只有在c-tor调用实际上非常重要时才使用方法B。谢谢。我觉得令人失望的是,该语言实现了诸如复制省略和移动语义等有用功能,然后阻止它们一起使用!有点像一手给予,另一手拿走。你能给m吗更多关于为什么推荐方法
A
而不是B的详细信息?这只是因为使用方法A
只需编写值重载?@Vasilly.Prokopyev对于新手来说,它更简短、更容易阅读。你能解释为什么函数调用不明确吗?:)@BaranKarakus是的,这正是发生的事情。你知道为什么函数调用是不明确的吗?我有一个类似的问题,无法解释为什么我们在这里有歧义。我本以为只要参数是右值,就会调用第二个函数,否则就会调用第一个函数。