用std::move执行就地排列
Performance of In-place permutation with std::move
我写了一个就地排列算法[TAOCP3中的一个练习],其中内环是
template<typename T>
void inplace_permute(T *pT, int *P, const int n)
{
// part of the inner loop
pT[j] = std::move(pT[k]);
P[j] = j;
// more logic to update j, k, etc.
}
这里,pT
是要排序的元素的阵列,P
是排列表,n
是元素的数量。
如果T是复杂类型,例如字符串,std::move
会提高性能吗?同样重要的是,如果T是基元类型(例如int?)
我将您的问题总结为:
std::move
做什么?
基本上,std::move
可以使用Move构造函数和Move Assignment运算符。
通常,它们接近于按位复制(它们是而不是恰好一个),因此性能通常与类的sizeof
有关。
因此,如果std::move(someint)
和std::move(somestring)
具有相似的大小,即使其中一个是内置类,另一个是用户类,它们也会具有相似的性能。
不过也有一些不同。
- 在内置设备上,移动只是按位复制。由于移动自值未指定,因此不需要归零。移动后,您可能希望为其指定一个已知值(0或其他值)
- 对于通常具有资源(这样一个动态分配的缓冲区)的用户类,移动意味着:清理已移动到的实例(用于分配),制作一个有点位的副本,重置已移动的实例。所以还有更多的工作要做
为了理解这一点,我们可以用一个字符串实现示例来说明:
class String {
public:
// Many things
String(String&& right);
String& operator=(String right);
friend void swap(String& left, String& right);
private:
// On 64 bits platform, 4x as big as an `int`
size_t capacity;
size_t size;
char* buffer;
};
// Move Constructor
String::String(String&& right):
capacity(right.capacity), size(right.size), buffer(right.buffer)
{
right = String(); // reset right
}
// Assignment Operator
String& String::operator=(String right) {
swap(*this, right);
return *this;
}
// Swap
void swap(String& left, String& right) {
using std::swap;
swap(left.capacity, right.capacity);
swap(left.size , right.size);
swap(left.buffer , right.buffer);
}
正如您所看到的,分配pT[j] = std::move(pT[k]);
的意思是(语义上):
- 创建临时(制作
pT[k]
的逐位副本) - 重置
pT[k]
- 在临时和
pT[j]
之间交换状态 - 销毁临时存储(通常释放从
pT[j]
继承的存储)
编译器应该或多或少能够将其优化为:
- 在
pT[j]
和pT[k]
之间交换状态 - 销毁
pT[k]
(只释放存储) - 在
pT[k]
中重建新实例
或者,粗略地说:
swap(ptj, ptk); // swap 3 fields
delete ptk.buffer; // might be a no-op
ptk = String(); // 0-out 3 fields
注意:这是一个玩具实现,在gcc上会更简单,在VC++上会更复杂,因为它们使用不同的数据表示。
如果T
有一个移动赋值运算符,它将用于右值,并可能提高性能。
如果类型没有移动赋值,但有复制赋值(如int
),则会复制该值。
相关文章:
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么不;名字在地图上是按顺序排列的吗
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 瓦尔格林德:数学函数"Conditional jump or move depends on uninitialised value(s)"
- Usages of std::move
- 在C++中对T*类型执行std::move的意外行为
- 按对象的特定方法按升序排列的C++优先级队列
- 关于std::move的使用,是否有编译警告
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 通过实例理解std::move及其目的
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 是否可以在 C++03 中定义'move-and-swap idiom'等效项
- 找到具有最多子串栅栏的字符串排列
- 返回一个带有 std::move 的对象并链接函数
- '[](std::list& list)<int>{return std::move(list)}(list)' 是否保证将 'list' 留空?
- 重新排列单线以形成闭合多边形?
- 为什么字符串的 move() 会改变内存中底层数据的位置?
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 在数组中输入 n 个整数的列表,并以类似于钟摆来回移动的方式排列它们. 输入-1 3 2 5 4,输出5 3 1 2 4
- 用std::move执行就地排列