我想知道我是否正确使用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] = ...
我可以进一步优化吗?
答案 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个副本。如果你想成为无可否认的最快,那么move
和const&
的每个组合都会有重载,但代码太多了。
我将通过移动获得什么?
假设&&
只包含3个整数/浮点数/双打,你将无法获得任何收益。基本类型不会从const&
获得任何内容,它与副本相同。
移动的最大好处通常是你可以“窃取”动态分配的内存。想象一下Point3D
,它会动态分配一个数组并保存一个指向它的指针。当你move
它时,它可以简单地将该指针复制到新对象并使原始指针无效。复制时,它会在新对象中分配新内存,并将数组(可能逐个元素)复制到新数组中。成本差异很大:与仅复制指针相比,分配和复制数组的元素。
结论:对于您的类型,通过vector
可能是最快的方式。