我写了一个就地排列算法[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?)
答案 0 :(得分:3)
我将把你的问题总结为:
std::move
做了什么?
基本上,std::move
可以使用Move Constructor和Move Assignment Operator。
通常,它们接近按位副本(它们不正好一个),因此性能通常与类sizeof
相关。
因此,如果std::move(someint)
和std::move(somestring)
具有相似的大小,即使其中一个是内置的,另一个是用户类,也会有类似的性能。
虽然存在一些差异。
要理解,我们可以通过示例字符串实现来说明这一点:
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 ++上要复杂得多,因为它们使用不同的数据表示。
答案 1 :(得分:1)
如果T
有一个移动赋值运算符,那么它将用于rvalues并可能提高性能。
如果类型没有移动分配,但确实有复制分配(如int
),则会复制该值。