Consider support for a non-throwing swap.
STL中的swap算法:
namespace std{
template<typename T>
void swap(T& a,T& b)
{
T temp(a);
a=b;
b=temp;
}
}
复制动作无一必要。
考虑以指针指向一个对象,内含真正数据。
class WidgetImpl{
public:
...
private:
int a,b,c; //可能有许多数据,
std::vector<double> v; //意味复制时间很长
...
};
以下class使用pimpl(pointer to implementation)方法:
class Widget{
public:
Widget(const Widget& rhs);
Widget& operator=(const Widget& rhs)
{
...
*pImpl=*(rhs.pImpl);
...
}
...
private:
WindgetImpl* pImpl; //指针,所指对象内含widget数据
};
一旦要置换两个widget对象值,只需要置换pImpl指针。缺省的swap算法得复制三个Widgets,三个WidgetImpl.
将std::swap针对Widget特化:
namespace std{
template<> //全特化:total template specialization
void swap<Widget>(Widget& a,Widget& b) //<Widget>表示特化系对"T 是Widget"而设计
{
swap(a.pImpl,b,pImpl);
}
}
无法通过编译,指针为private.
我尝试用member function取代。
假如Widget和widgetImpl都是class template:
namespace std{
template<typename T>
void swap<Widget<T>>(Widget<T>& a,Widget<T>& b)
{a.swap(b);}
}
c++只允许class template偏特化(partially specialize,function template行不通。
试着重载:
namespace std{
template<typename T>
void(Widget<T>& a,Widget<T>& b)
{a.swap(b);}
}
重载没有问题,但是std的内容完全由C++标准委员会决定,不可随意添加。
可以声明一个non-member swap调用member swap,但不再将non-member声明为特化版本或重载版本。
namespace WidgetStuff{
...
template<typename T>
class Widget{...};
...
template<typename T>
void swap(Widget<T>& a,Widget<T>& b)
{a.swap(b);}
}
现在任何地点任何代码如果打算置换两个Widget对象,调用swap,c++名称查找法则(name lookup rules;
更具体地说是所谓的argument-dependent lookup或Koenig lookup法则)会找到WidgetStuff内的Widget专属版本。
我们希望调用T专属版本,并在该版本不存在的情况下调用一般化版本。
template<typename T>
void doSomething(T& obj1,T& obj2)
{
usingstd::swap;
...
swap(obj1,obj2);
...
}
一旦编译器看到swap的调用,便查找适当的swap调用。C++名称查找法则确保将global作用域或T所在的命名空间内的任何T专属的swap.