C++ 当编写自己的swap()函数/方法有性能优势时
假设我有这样一节课:C++ 当编写自己的swap()函数/方法有性能优势时,c++,swap,C++,Swap,假设我有这样一节课: struct A{ std::string a; std::string b; std::string c; std::string d; }; 如果我使用std::swap,它可能会执行以下操作: // pseudo-code: void std::swap(A &a, A &b){ A tmp = std::move(a); a = std::move(b); b = std::move(tmp); } 它将使用默认
struct A{
std::string a;
std::string b;
std::string c;
std::string d;
};
如果我使用std::swap
,它可能会执行以下操作:
// pseudo-code:
void std::swap(A &a, A &b){
A tmp = std::move(a);
a = std::move(b);
b = std::move(tmp);
}
它将使用默认的c-tor构造“空”对象tmp
——通常是廉价的操作。然后它有望移动3次,除非在疯狂的情况下移动到复制
但是,如果我自己进行交换:
void swap(A &a, A &b){
std::swap(a.a, b.a);
std::swap(a.b, b.b);
std::swap(a.c, b.c);
std::swap(a.d, b.d);
}
它肯定会使用更少的内存,但它仍然需要构造空std::string
-4次
我可以发狂,用singlestd::string
就可以了
在所有情况下,这看起来并不是很大的改善
我能想到的唯一合适的情况是,默认的c-tor是否贵得离谱。我说的对吗?你不能说你需要或者永远不应该自己交换
,这完全取决于上下文。在您的示例中,它很可能是不必要的,但类的逻辑可能更复杂
假设您有一个类,它持有指向某个数据结构的指针,并且有许多与该结构相关联的度量,每个度量都需要很长的时间来计算,并且需要大量的空间来存储,这些度量在对数据进行某些计算时用作临时度量(我知道下面的例子可能是一个设计糟糕的类,但它应该能说明这个想法):
class-MyClass
{
公众:
void doSomeWork()
{
//使用_metricsOneValue和_metricsTwoValue作为临时值,
//调用将它们用作临时变量的其他函数,等等。
}
私人:
//仅用于doSomeWork及其调用的函数。
//值覆盖每个调用。
SomeBigClass_metricsOneValue;
SomeBigClass _metricsTwoValue;
其他类别*_数据;
}
现在,假设您需要swap()
这个类的两个实例。最简单的实现将复制所有内容,包括旧的度量,实际上,这些度量目前并不需要,因为它们将在下次调用doSomeWork()时被覆盖无论如何。
因此,在这种情况下,您可以通过交换指向数据结构的指针来优化交换。实现您自己的交换
1函数有一个好处,那就是在赋值操作符中使用复制和交换习惯用法来管理/传输动态分配的内存
如果您有以下课程:
#include <algorithm> // std::copy
#include <cstddef> // std::size_t
class MyArray{
public:
// (default) constructor
MyArray(std::size_t size = 0)
: mSize(size), mArray(mSize ? new int[mSize]() : 0)
{ }
// copy-constructor
MyArray(const MyArray& other)
: mSize(other.mSize), mArray(mSize ? new int[mSize] : 0),
{ std::copy(other.mArray, other.mArray + mSize, mArray); }
// destructor
~MyArray(){ delete [] mArray; }
private:
std::size_t mSize;
int* mArray;
};
你可以做:
MyArray& operator=(MyArray other){
swap(*this, other);
return *this;
}
2.要安全交换类的成员,请执行以下操作:
注:本答案中的见解借鉴自
1交换函数是一个非抛出函数,它将一个类的两个对象(成员对成员)交换。我们可能会尝试使用std::swap
而不是提供我们自己的,但这是不可能的;std::swap
在其实现中使用复制构造函数和复制赋值操作符,我们最终会尝试根据赋值运算符本身定义赋值运算符!我希望是一个正常的std::swap(std::string&,std::string&)
实现在没有任何临时变量的情况下进行交换。它应该只能够交换指针,尽管我承认小字符串优化可能会在某些实现的特定工作中遇到麻烦
您可以始终使用std::string::swap
member函数,我的意思是,否则,它有什么意义?:)
无论如何,您都需要实现它,即使它只是move构造函数的一部分,否则默认的std::swap(A&,A&)
实现不能做很多事情
总之,是的,您应该编写自己的swap
函数,是的,您应该使用它来调用标准swap功能。因为两者都需要,所以不需要进行性能比较。您没有调用默认构造函数。您正在调用移动构造函数。
MyArray& operator=(const MyArray& other){
if (this != &other){
// get the new data ready before we replace the old
std::size_t newSize = other.mSize;
int* newArray = newSize ? new int[newSize]() : 0;
std::copy(other.mArray, other.mArray + newSize, newArray);
// replace the old data
delete [] mArray;
mSize = newSize;
mArray = newArray;
}
return *this;
}
MyArray& operator=(MyArray other){
swap(*this, other);
return *this;
}
friend void swap(MyArray& first, MyArray& second){
using std::swap;
// by swapping the members of two classes,
// the two classes are effectively swapped
swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);
}
void swap(A &a, A &b)
{
a.a.swap(b.a);
a.b.swap(b.b);
a.c.swap(b.c);
a.d.swap(b.d);
}