重载传递值和传递右值参考值

时间:2015-10-08 16:39:46

标签: 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_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的全新副本(或调用copy copy以避免这样做在适当的地方,例如参数实际上是函数的返回值),然后将副本移动到本地数据成员中,从而避免进一步复制。

但是,如果我尝试使用第一个重载实际将对象移动到我的类中:

{
    MyClass        theDestination;
    MyMoveableType theObject
    ...
    // ...Various actions which populate theObject...
    ...

    TheDestination.setParameter(std::move(theObject));
    ...
}

...然后在我尝试的每个编译器上,我得到了一个错误:

call to member function 'setParameter' is ambiguous

现在我可以看到,将rvalue引用传递给第二个重载实际上是完全合法的,如果我没有提供第一个重载,那就是我期望编译器做的事情,而不会发出警告。即便如此,我希望编译器能够清楚地知道这段代码的意图是什么,因此我希望它会选择第二次重载作为最佳匹配。

我可以通过重新定义第二个构造函数来获取const引用并取消std :: move来消除错误(尽管它不会是一个错误 留下来;编译器会忽略它)。这样可以正常工作,但我失去了利用复制省略的机会。这可能是 该特定应用在性能方面具有重要意义;正在讨论的对象是在30处流过的高分辨率视频帧 每秒帧数。

在这种情况下,我能做些什么来消除重载的歧义,因此我的例行程序还包含值传递和右值参考版本?

1 个答案:

答案 0 :(得分:0)

  

目的很明显,第一次重载将newParameter的内容从子程序链调用newParameter对象的任何地方移动,而第二次重载则创建一个全新的副本

你真的不怎么做。你有两个理智的选择:

方法A

你只是写了值重载然后从它移开 - 这意味着你总是要付出一个构造函数的价格,无论是移动还是复制。

方法B

您为(const T&)(T&&)写了重载。这样你就可以复制第一个并使用完美转发跳过第二个移动CTOR。

我建议将A作为默认值,而B仅在c-tor呼叫实际上非常重要时使用B.