条款25:考虑写一个不抛出异常的swap函数

考虑如下代码

class WidgetImp1 { //针对Widget数据设计的class,细节不重要
public:
	//...
private:
	int a, b, c;
	std::vector<double>	 v;	
};

class Widget {
public:
	Widget(const Widet& rhs);
	Widget& operator=(const Widget& rhs) {
		//...
		*pImpl = *(rhs.pImpl);
	}
private:
	WidgetImpl* pImpl;	
};

当我们要交换Widget对象值的时候,我们唯一要做的就是交换其成员pImpl指针,但是缺省的swap算法不知道这一点,不但会复制三个widget,还会复制三个WidgetImpl对象,效率十分低下;

我们希望告诉std::swap,当交换Widget时,真正要做的是交换内部的pImpl指针;办法就是将std::swap针对Widget特化

namespace std {
    template<>
    void swap<Widget> (Widget& a, Widget& b){
        swap(a.pImpl, b.pImpl);
    }
}

template<>代表它是针对std::swap的一个全特化,函数名称之后的<Widget>代表这一特化版本系针对"T是Widget"而设计的;通常我们不能够(不被允许)改变std命名空间内的任何东西,但是可以(被允许)为标准templates(如swap)制造特化版本;

上述特化swap还无法通过编译,因为pImpl是私有成员,无法访问,解决办法是令Widget声明一个名为swappublic成员函数做真正的交换工作,然后做特化工作

class Widget {
public:
	//...
	void swap(Widget& other) {
		using std::swap;
		swap(pImpl, other.pImpl);
	}
};

namespace std {
    template<>
    void swap<Widget> (Widget& a, Widget& b){
		a.swap(b);
    }
}

现在我们假设WidgetWidgetImpl都是class templates而非classes:

template<typename T>
class WidgetImpl {//...}

template<typename T>
class Widget {//...}

我们可以像之前一样在Widget放个swap成员函数,但是在特化std::swap时遇到了麻烦:

namespace std {
	template<typename T>
	void swap< Widget<T> >(Widget<T>& a, Widget<T>& b){ // 错误!
		a.swap(b);
	}
}

我们企图偏特化一个function template,但是C++之允许对class templates偏特化;当你打算偏特化一个function template时惯常做法是简单地为它添加一个重载版本:

namespace std {
	template<typename T>
	void swap(Widget<T>& a, Widget<T>& b){ // 重载版本
		a.swap(b);
	};
}

一般而言,重载function template没有问题,但是std是个特殊的命名空间,客户可以全特化std内的template但不可以添加新的templatesstd里头;解决办法是我们还是声明一个 non-member的swap让它调用member的swap,但不再将那个non-member声明为std::swap的特化版本:

namespace WidgetStuff {
	// ...
	template<typename f>
	class Widget{ //...};
	//...
	template<typename T>
	void swap(Widget<T>& a, Widget<T>& b){ // 这里并不属于std命名空间
		a.swap(b);
	};
}

最后调用swap时应该针对std::swap使用using声明式,然后调用swap并且不带任何"命名空间资格修饰",如下:

template<typename T>
void doSomething(T& a,T& b) {
	using std::swap // 令std::swap在此函数内可用
	//...
	swap(a, b);
	//...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值