一、非模板安全的代码
#include <iostream>
using namespace std;
template <typename T>
class wrapper
{
public:
wrapper() { }
T get() { return m_value; } //part 2
void set(T const &value) { m_value = value; } //part 3
private:
T m_value; //part 1
wrapper(wrapper const &);
wrapper& operator=(wrapper const &);
};
int main(int argc, char* argv[])
{
return 0;
}
二、模板安全分析与解决
2.1 模板安全分析
如果T为int,即wrapper<int>,没有任何问题。
如果T是一个类,会有3个潜在的模板安全问题:
1. T m_value 会调用类T的构造函数,可能会抛出异常;
2. T get() { return m_value; } 会调用类T的构造函数,构造T的一个临时对象,可能会抛出异常;
3. void set(T const& value) { m_value = value; } 会调用类T的赋值运算符,可能会抛出异常。
2.2 T m_value 解决办法
1. 构造函数中,不能抛出function-try异常。
2. 将隐式构造改成显式构造,即:
wrapper() : m_value(NULL)
{
m_value = new T;
}
3. m_value = new T可能会抛出异常:
wrapper() : m_value(NULL)
{
try { m_value = new T; }
catch (...) { }
}
4. 需要增加析构时释放函数:
调用delete m_value析构时如果抛出异常,需要手动delete m_value(catch(...) { })
如果catch(...) { }中的delete m_value再抛出异常,程序将2次处于异常状态,会调用terminate()。
~wrapper() throw()
{
try { delete m_value; }
catch (...) { operator delete(m_value); }
}
2.3 T get() { return m_value; } 解决办法
1. 将隐式构造改为显式:
void get(T& value)
{
value = m_value;
}
2. value = m_value赋值运算符, 可能会抛出异常:
void get(T& value)
{
try { value = m_value; }
catch(...) { }
}
3. 即便处理的异常,返回的value处于不确定状态,调用者不知道其是什么状态:
用返回值,来标示value,是赋值完成,还是没有完成。
bool get(T& value)
{
bool error = false;
try { value = m_value; }
catch(...) { error = true; }
return error;
}
2.4 void set(T const& value) { m_value = value; } 解决办法
参照2.3节的,第2、3步。
三、模板安全的代码
#include <iostream>
using namespace std;
template <typename T>
class wrapper
{
public:
wrapper() throw() : m_value(NULL)
{
try { m_value = new T; }
catch (...) { }
}
~wrapper() throw()
{
try { delete m_value; }
catch (...) { operator delete(m_value); }
}
bool get(T& value) const throw() { return assgin(value, *m_value); }
bool set(const T& value) throw() { return assgin(*m_value, value); }
void output() { cout<<m_value<<endl; }
private:
T* m_value;
bool assign(T& to, T const & from) throw()
{
bool error(false);
try { to = from; }
catch (...) { error = true; }
return error;
}
wrapper(wrapper const &);
wrapper& operator=(wrapper const &);
};
int main(int argc, char* argv[])
{
return 0;
}