当编写自己的 swap() 函数/方法具有性能优势时
when there is performance benefit for writing own swap() function / method
假设我有这样的类:
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 倍!!
我可以狂野,用单std::string
做到.
在所有情况下,它看起来都不像很大的改进。
我能想到的唯一适当情况是默认 c-tor 是否贵得离谱。我说的对吗?
你不能说你需要,或者永远不应该,制作自己的swap
,这完全取决于上下文。在您的示例中,这很可能是不必要的,但您的类的逻辑可能更复杂。
假设你有一个类,它保存着指向某个数据结构的指针,并且有很多与该结构关联的指标,每个指标都需要很长时间来计算,并且需要大量的空间来存储,并且这些指标在对数据进行一些计算时用作临时指标(我知道以下示例可能是一个蹩脚设计的类, 但它应该说明这个想法(:
class MyClass
{
public:
void doSomeWork()
{
//uses _metricsOneValue and _metricsTwoValue as temporaries,
//calls other functions that use them as temporaries too, etc.
}
private:
//used only in doSomeWork and functions called by it.
//Value overwritten each call.
SomeBigClass _metricsOneValue;
SomeBigClass _metricsTwoValue;
<...>
SomeOtherClass * _data;
}
现在假设您需要swap()
此类的两个实例。最直接的实现将复制所有内容,包括旧指标,实际上,目前不需要这些指标,因为下次您调用doSomeWork()
时它们将被覆盖。因此,在这种情况下,您只需将指针交换到数据结构即可优化swap
。
我希望一个理智的std::swap(std::string&, std::string&)
实现可以在没有任何临时的情况下进行交换。它应该只是能够交换指针,尽管我承认小字符串优化可能会在某些实现的特定工作中抛出扳手。
您可以随时使用 std::string::swap
成员函数,我希望更多地利用这种令人愉快的"优化"。我的意思是,否则,它有什么意义?:)
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);
}
无论如何,您都需要实现它,即使它只是您的 move 构造函数的一部分,否则默认的 std::swap(A&, A&)
实现无法做任何事情。
总之,是的,您应该编写自己的swap
函数,是的,您应该使用它来调用标准交换功能。因为两者都需要,所以没有性能比较。
自己的 swap
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;
};
1. 实现赋值运算符
而不是:
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;
}
2. 要安全地交换类的成员:
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);
}
注:本答中的见解借用于此。
1 交换函数是一个非抛出函数,它交换类的两个对象,成员到成员。我们可能会想使用std::swap
而不是提供我们自己的,但这是不可能的; std::swap
在其实现中使用了复制构造函数和复制赋值运算符,我们最终会尝试根据自身来定义赋值运算符!
- 哪种方法更好,性能明智
- 不同的类或结构初始化方法之间的性能差异是什么?
- std::map 索引运算符与插入方法的性能
- 在.cpp文件中定义方法而不是在 C++ 的 .h 文件中定义方法时,如何提高代码的性能?
- 在类实例或方法的上下文中调用函数以进行性能分析
- 检查从查询返回的任何行是否包含在字符串中的最高性能方法?
- Union-Find方法性能,迭代与递归
- 虚拟方法与std ::功能成员变量在性能方面
- 是否有更好的方法(性能提高 /内置功能)获得矩形的旋转角度
- 类方法VS类静态函数VS简单函数-性能方面
- 清除rwtexture2d的大多数性能方法
- boost::asio::strand post方法性能
- 将特征矩阵转换为 c 数组以便我可以使用 gsl 的性能高效方法是什么
- 这种错误检查方法的性能会不会太高
- 为性能库制作高效包装器的智能方法
- 就百分比而言,这两种方法之间的平均性能差异有多大
- 无法为C++方法添加性能探测
- Linux 性能监控,任何监视每个线程的方法
- 初始化方法与构造函数加赋值的方法——性能有什么不同?(C++)
- 测试值是否在阈值范围内的最佳方法(性能方面)是什么