如果一个类定义了自己的swap,那么算法将使用类自定义版本。否则,算法将使用标准库定义的swap。虽然与往常一样我们不知道swap是如何实现的,但理论上很容易理解,为了交换两个对象我们需要进行依次拷贝和两次赋值。例如,交换两个值HasPtr对象的代码可能像下面这样:
HasPtr temp =v1;
v1=v2;
v2=temp;
这段代码将原来的v1中的string拷贝了两次—第一次是HasPtr的拷贝狗杂函数将v1创建给v1拷贝为temp,第二次是赋值运算将temp赋予v2。将v2赋予v1的语句还拷贝了原来v2中的string。如我们所见,拷贝一个值为HasPtr会分配一个新的string并将其拷贝到HasPtr指向的位置。 理论上,这些内存分配都是不必要的。我们更希望swap交换指针,而不是分配string的新副本。即,我们希望这样交换两个HasPtr
string * temp=v1.ps;
v1.ps=v2.ps;
v2.ps=temp;
编写我们自己的swap函数
class HasPtr{
friend void swap(HasPtr&,HasPtr&);
};
inline
void swap(HasPtr &lhs,HasPtr &rhs)
{
using std::swap;
swap(lhs.ps,rhs.ps);
swap(lhs.i,rhs.i);
}
我们首先将swap定义为friend,以便能访问HasPtr的(private的)数据成员,由于swap的存在就是为了优化代码,我们将其声明为inline函数、swap的函数体对给定对象的每个数据成员调用swap。我们首先swap绑定到rhs和lhs的对象的指针成员,然后是int成员
swap函数应该调用swap,而不是std::swap
如果一个类的成员有自己类型特定的swap函数,调用std::swap就是错误的
在赋值运算符中使用swap
定义swap的类通常使用swap来定义它们的赋值运算符。这些运算符使用了一个名为拷贝并交换的技术。这种技术将左侧运算对象与右侧运算对象的一个副本进行交换
HasPtr& HasPtr::operator=(HasPtr rhs)
{
swap(*this, rhs);
return *this;
}
|