如何有效地移动具有大量 POD 成员的类?例子:
struct{
int a1;
int a2;
int a3;
...
...
...
};
“移动”是指行为类似于移动语义(std::move)。
POD 不移动,它们只是复制。因为没有间接性。因此,只需使用普通赋值,并要求编译器针对您想要的任何效率进行优化。记住要系统地测量之前(你在地球上做的不同)和之后。还要考虑浪费的程序员时间,也就是金钱,是否值得微优化。
这个问题暴露出对 C++11 中的运动的用途缺乏了解。
当您复制具有指针或以其他方式拥有资源的对象时,有两种方法可以进行该复制。您可以复制指针/资源引用,也可以分配新对象/资源并将原始对象/资源的值复制到新对象/资源中。
在第一种情况下,您会得到两个引用同一对象的对象。Qt 经常这样做。如果您使用一个对象来修改它所引用的内容,那么您也在修改另一个对象。您通常需要某种引用计数器,以免双重删除指针或双重释放资源。
在第二种情况下,您将得到两个完全独立的对象。这通常称为“值语义”,因为如果您将一个 POD 复制到另一个 POD 中,之后您将拥有两个完全独立的对象。改变一个不会改变另一个。
移动语义是一种 C++11 机制,允许通常具有值语义的对象在某些条件下具有引用语义。它本质上允许一个对象窃取另一个对象实例引用的指针/资源。
例如,采取std::vector
; 这只是动态分配和调整大小数组的包装。与大多数 C++ 标准库对象一样,vector
实现值语义。如果复制 a vector
,则新向量必须分配一个新数组并将每个元素从旧数组复制到新数组中。完成后,您将拥有两个完全独立的数组。
移动语义是一种将 a 中包含的数组vector
转移到另一个数组的方法。操作后,移动源对象是“空的”(技术上处于未定义状态,但它与它分配的数据有效分离)。现在新vector
的指针与旧的指针完全相同vector
。newvector
将删除它没有分配的内存。
如您所见,这都是基于对象拥有资源的概念。vector
分配并拥有一个数组;它的析构函数会摧毁它。这就是你定义所有权的方式。运动是关于转移所有权。
POD 不能表示指针或资源的所有权,因为 POD 必须具有普通的析构函数(即:不做任何事情的析构函数)。因为 POD 不能表达所有权,所以没有东西可以移动。如果对象不拥有任何东西,则不能在对象之间转移所有权。
您必须发挥工程判断力。想象一个例子,你正在谈论是否使用 astd::array<int, N>
或 a std::vector<int>
with N
items,其中N
是编译时常量。
当N
很小的时候,std::array<int, N>
是明显的赢家,因为没有堆分配。副本(以及相当于副本的移动)很便宜。
当N
非常大时,std::vector<int>
是明显的赢家,因为尽管有一个堆分配,并且vector
无论N
.
时N == 3
,毫无疑问哪个是更好的选择。当N == 3,000,000
毫无疑问哪个是更好的选择时。
作为设计师,你的工作就是走进这两个极端之间的灰色地带并做出正确的决定。没有永远正确的决定。针对您预期的用例的性能测量有很长的路要走。用于<chrono>
那些性能测量。如果您不知道是什么<chrono>
,请搜索 stackoverflow。
创建一个类以指向具有 POD 的类并在前者上使用 std::move 。