传递右值作为参考

时间:2016-01-07 12:49:48

标签: c++ qt c++11 rvalue-reference

我有一些从我的svn repo下载的Qt代码。我工作了一段时间,但我确信它曾用于编译。

我有一个新版本的Qt和编译器(就像我上次的那样)。我目前的编译器是:mingw 4.9.2 32位。

所以这是我的问题代码:

QByteArray dataBlock = audioTestFile.read(PACKET_SIZE_TO_ENCODE);
// This line is the issue
uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()));

其中:

typedef std::vector<uint8_t> uint8Vect_t;

uint8Vect_t encodeData(uint8Vect_t &dataBuff);

所以你可以在这里看到我有一个函数encodeData(),它接受一个参数uint8Vect_t &(通过ref传递)。我正在传递一个临时变量(我认为是一个rvalue),它是使用std :: vector构造函数(其中一个需要两个迭代器)从QByteArray dataBlock迭代器(我已经测试过)开始创建的。

然而,我收到错误:

  

../ audioTest / txaudiostream.cpp:在成员函数'void中   CTxAudioStream :: playFile()':.. / audioTest / txaudiostream.cpp:212:94:   错误:没有匹配的函数用于调用   'CTxAudioStream :: encodeData(uint8Vect_t)'                uint8Vect_t testVect = encodeData(uint8Vect_t(dataBlock.begin(),dataBlock.end()));                                                                                                 ^ ../audioTest/txaudiostream.cpp:212:94:注意:候选人是:   ../audioTest/txaudiostream.cpp:36:13:注意:uint8Vect_t   CTxAudioStream :: encodeData(uint8Vect_t&amp;)uint8Vect_t   CTxAudioStream :: encodeData(uint8Vect_t&amp; dataBuff)                ^ ../audioTest/txaudiostream.cpp:36:13:注意:参数1从'uint8Vect_t {aka std :: vector}'到'uint8Vect_t&amp; {aka std :: vector&amp;}'

基本上它是说我无法从uint8Vect_t转换为uint8Vect_t&amp;。但是如果我将一个类型为uint8Vect_t的变量传递给函数(而不是contructor / temp变量的返回值),那么这就可以了。

我认为在c ++ 11中你可以传递rvalues ..但我显然在这里遗漏了一些东西。任何人都可以解释:

  1. 为什么这是错的?
  2. 什么是高效/优雅(可读)的解决方案?

4 个答案:

答案 0 :(得分:13)

您的问题是

uint8Vect_t encodeData(uint8Vect_t &dataBuff);

您在这里引用uint8Vect_t。这适用于普通变量,但uint8Vect_t(dataBlock.begin(), dataBlock.end())是临时对象,不能绑定到左值引用。

如果encodeData()没有更改dataBuff,那么最简单的解决方案是采用可以绑定到临时文件的const &

uint8Vect_t encodeData(const uint8Vect_t &dataBuff);

如果您必须更改dataBuff的内容,则必须编写另一个版本的encodeData(),其中包含右值参考

uint8Vect_t encodeData(uint8Vect_t &&dataBuff);

这将允许函数绑定到临时向量,您可以在函数中处理它,就像使用普通向量一样。

我相信你看到这个的原因是你的旧编译器是Microsoft Visual Studio的一个版本。 MSVS具有非标准扩展,默认情况下处于启用状态,允许临时对象绑定到左值引用。您可以在Non-const reference bound to temporary, Visual Studio bug?

了解更多相关信息

添加此项以向您展示如何更改encodeData()以获取右值参考而无需编写新函数。

#include <iostream>
#include <vector>

std::vector<int> modify(std::vector<int>& foo)
{
    for (auto & e : foo)
        e *= 2;
    return foo;
}

std::vector<int> modify(std::vector<int>&& foo)
{
    return modify(foo);
}


int main()
{
    std::vector<int> foo = modify({ 1,2,3,4,5 });
    for (const auto & e : foo)
        std::cout << e << " ";
}

Live Example

在上面的示例modify({ 1,2,3,4,5 })调用modify(std::vector<int>&& foo),然后在函数foo中调用lvaue。然后我们返回传递&#34; new&#34;的结果。左值modify(std::vector<int>& foo)然后返回修改后的矢量。

答案 1 :(得分:6)

使用时

encodeData(uint8Vect_t(dataBlock.begin(), dataBlock.end()))

传递给函数的向量是临时对象,引用不能绑定到临时对象。

如果函数不修改参数,那么简单的解决方案就是使它成为对常量对象的引用:

uint8Vect_t encodeData(uint8Vect_t const& dataBuff);

对常量对象的引用可以绑定到临时对象。

答案 2 :(得分:2)

你想对你传递的对象做什么?

当你把它当作uint8Vect_t &dataBuff时,你应该意味着要对它进行持久的修改,如果它是暂时的,这是没有意义的。

当您将其视为uint8Vect_t const&dataBuff时,表示您想从中复制而不是修改它,可能是您想要的

当你把它作为uint8Vect_t dataBuff时,你应该意味着你需要你自己的本地临时副本,按照自己的意愿使用然后扔掉,这应该足够重要,值得复制。

当你把它当作uint8Vect_t &&dataBuff时,你应该意味着你要从一个临时对象进行非持久性修改(例如内容窃取),调用者有效地承诺在你完成它之后扔掉它。

最后一个选择是C ++ 11中用于传递rvalues的新选项。

答案 3 :(得分:0)

任何函数的返回值都是一个临时对象(右值),您不能将临时对象作为引用传递。

下面的代码将产生与我们试图将“ saurabh”(临时对象)作为引用类型传递相同的错误。

void fun(string& name){
  //statements;
}

int main(){
    fun("Saurabh");
    return 0;
}