std :: vector和Move构造函数

时间:2013-11-23 15:43:23

标签: c++11 stl move-semantics rvalue-reference

我想使用C ++ 11移动语义。我写了下面的课:

class ColorM
{
public:
    ColorM(float _r, float _g, float _b, float _a){
        qDebug()<<"Constructor";
        r = _r;
        g = _g;
        b = _b;
        a = _a;

        m = new float[16];
    }


    ColorM(const ColorM &other){
        qDebug()<<"Copy Constructor";
    }


    ~ColorM(){
        if (m != nullptr)
        {
           qDebug()<<"Deleting resource.";
           // Delete the resource.
           delete[] m;
        }
    }

    // Move constructor.
    ColorM(ColorM&& other)
    {
        qDebug()<<"Move Constructor";
       r = other.r;
       g = other.g;
       b = other.b;
       a = other.a;
       m = other.m;


       other.m = nullptr;
    }


    float r;
    float g;
    float b;
    float a;

    float *m;
private:
};

当我尝试:

std::vector<ColorM> vec;
vec.push_back(ColorM(0.1, 0.6, 0.3, 0.7));
vec.push_back(ColorM(0.2, 0.6, 0.3, 0.7));
vec.push_back(ColorM(0.3, 0.6, 0.3, 0.7));

我有复制构造函数调用。我做错了什么? 我以this为例。并用g ++编译它。

以下是我用于测试的QT项目:http://wikisend.com/download/261514/MoveConstructor.zip

2 个答案:

答案 0 :(得分:1)

您可以使用std::vector<T>::emplace_back功能

std::vector<ColorM> vec;
vec.emplace_back(0.1, 0.6, 0.3, 0.7);  // Will call 
vec.emplace_back(0.2, 0.6, 0.3, 0.7);  //     ColorM::ColorM(float _r, float _g, ..) ctor
vec.emplace_back(0.3, 0.6, 0.3, 0.7);

或(使用ColorM移动构造函数)

std::vector<ColorM> vec;
vec.emplace_back(ColorM(0.1, 0.6, 0.3, 0.7));  // Should be equivalent to your code
vec.emplace_back(ColorM(0.2, 0.6, 0.3, 0.7));
vec.emplace_back(ColorM(0.3, 0.6, 0.3, 0.7));

注意:我不同意user2485710的回答。由于ColorM(0.1, 0.6, 0.3, 0.7)的{​​{1}}参数是临时的,我希望编译器将其识别为r值引用并使用{{1}应用移动构造函数而不使用 },自push_back has an overload for r-value references

换句话说,std::movepush_back个对象应避免使用emplace_back之类的副本;在ColorM的情况下,您必须在适当的位置构建。

使用上面的第二个版本,与push_back相比,您应该获得更好的诊断消息,即在编译时失败而不是复制构造函数的这种微妙的意外使用。

答案 1 :(得分:0)

这是因为你的构造函数的签名和你push_back()操作的参数。

简而言之T()生成类型为T的对象的新实例,如果此实例与标签/变量无关,则实例仍然是unnamed,但是他没有不改变它自己的类型,它始终是T类型的“某种东西”(它甚至可以被视为T&const T&但这不是本主题的参数。)

要获得T&&cast所需的T&&签名,并且在C ++ 11中,这是std::move的工作,这也是一种无条件的演员,所以在任何地方都很容易使用。

您可以将std::move添加到您班级内的构建工具或push_back的通话中。