一个泛型丢失例子的思考

2013年4月8日 由 Creater 留言 »

模板提供了编译时期的多态行为,而且编码灵活,大大降低了代码编写量。但是使用的时候这里介绍两个注意点:
1.对于模板编写的类,类的定义与类成员函数的实现必须放在同一个文件中,需要使用该模板的地方直接包含该文件即可。当然万事都不是那么绝对,在支持export的编译器上,将类的定义与成员函数的实现可以放在两个文件中,在每个成员函数实现前面加上export.
2.无意之间造成的泛型缺失,比如下面的代码:

#include <vector>
#include <string>
#include <iostream>
using namespace std;

template<class T>
void destory(T* p)
{
	p->~T();
}

template<class Iter>
void destory(Iter first, Iter last)
{
	while(first != last)
	{
		destory(first);
		++ first;
	}
}

int main()
{
	int a[5];
	destory(a, a + 5);
}

对于第一个destory,会根据传入的模板参数来调用析构函数达到释放资源的目的;对于第二个destory来说,则是第一个destory的重载,内部也是会调用第一个destory的。这种用法在标准模板库(STL)里很常见。目测这两个函数都是没有问题。

但是,如果主函数为如下:

int main()
{
	vector<int> vec;
	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);
	destory(vec.begin(), vec.end());
}

以上代码会有编译错误:
exception.cpp: 在函数‘void destory(Iter, Iter) [with Iter = __gnu_cxx::__normal_iterator >]’中:
exception.cpp:28:32:从此处实例化
exception.cpp:17:3: 错误:对‘destory(__gnu_cxx::__normal_iterator >&)’的调用没有匹配的函数

错误原因:第二个模板函数可以接收任意类型的模板参数;而第一个模板函数细细一看则发现只能接收指针类型的模板参数,这样无形直接导致泛型打折。

解决办法:既然第一个模板函数需要指针,我们则构造一个指针即可。

#include <vector>
#include <string>
#include <iostream>
using namespace std;

template<class T>
void destory(T* p)
{
	p->~T();
}

template<class Iter>
void destory(Iter first, Iter last)
{
	while(first != last)
	{
		destory(&*first);
		++ first;
	}
}

int main()
{
	vector<int> vec;
	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);
	destory(vec.begin(), vec.end());
}

关键的地方就是在第二个模板函数里边:destory(&*first),我们先解引用,然后再取地址。至此这样的问题解决了。

广告位

发表评论

你必须 登陆 方可发表评论.