我是否正确使用移动语义?有什么好处?

时间:2015-05-18 21:41:56

标签: c++ c++11 move move-semantics

我想知道我是否正确使用move语义:

class Vertex{
    protected:
        Common::Point3D position;
        Common::Point3D normal;
        Common::Point2D uv;
        Common::Point2D tangent;
    public:
        Vertex(Common::Point3D &&position, Common::Point3D &&normal, Common::Point2D &&uv, Common::Point2D &&tangent)
            : position(std::move(position)), normal(std::move(normal)), uv(std::move(uv)), tangent(std::move(tangent)){}
};

我将通过move在此处实现什么?比较代码(我也可以const &):

class Vertex{
    protected:
        Common::Point3D position;
        Common::Point3D normal;
        Common::Point2D uv;
        Common::Point2D tangent;
    public:
        Vertex(Common::Point3D position, Common::Point3D normal, Common::Point2D uv, Common::Point2D tangent)
            : position(position), normal(normal), uv(uv), tangent(tangent){}
};

将会阻止多少份副本以及哪些副本会发生?

我想使用这样的代码:

Vertex * vertices = new Vertex[10000];
vertices[0] = Vertex(Common::Point3D(1,2,3), Common::Point3D(4,5,6)...);
vertices[1] = ...

我可以进一步优化吗?

1 个答案:

答案 0 :(得分:1)

  

我想知道我是否正确使用了移动语义:

通过仅接受rvalue引用,您将限制将lvalues传递给此构造函数。您可能会很快发现您不能像预期的那样使用它。如果您按价值接受类型......

int num = 5;
char * point;

...您允许类的用户point = 8; Vertex(Common::Point3D position, Common::Point3D normal, Common::Point2D uv, Common::Point2D tangent) : position{std::move(position)} , normal{std::move(normal)} , uv{std::move(uv)} , tangent{std::move(tangent)} {} 进入构造函数变量,然后始终move进入您的成员变量。这意味着您将始终导致1次复制和1次移动或2次移动,具体取决于调用ctor的方式。或者,您可以选择copy,无论如何都会产生1个副本。如果你想成为无可否认的最快,那么moveconst&的每个组合都会有重载,但代码太多了。

  

我将通过移动获得什么?

假设&&只包含3个整数/浮点数/双打,你将无法获得任何收益。基本类型不会从const&获得任何内容,它与副本相同。

移动的最大好处通常是你可以“窃取”动态分配的内存。想象一下Point3D,它会动态分配一个数组并保存一个指向它的指针。当你move它时,它可以简单地将该指针复制到新对象并使原始指针无效。复制时,它会在新对象中分配新内存,并将数组(可能逐个元素)复制到新数组中。成本差异很大:与仅复制指针相比,分配和复制数组的元素。

结论:对于您的类型,通过vector可能是最快的方式。