一、通过导入新类型来预防错误
struct Day{
explict Day(int d)
: val(d){}
int val;
}
struct Month{
explict Month(int d)
: val(d){}
int val;
}
struct Year{
explict Year(int d)
: val(d){}
int val;
}
class Date{
public:
//Date(int m,int d,int y);//容易导致错误的用法
Date(const Month& m,const Day& d,const Year& y);
...
};
Date d(30,3,1995); //错误!不正确的类型
Date d(Day(30),Month(3),Year(1995)); //错误!不正确的类型
Date d(Month(3),Day(30),Year(1995));
};
进一步改进:束缚对象值。使用enum可以,但是不具备类型安全性,可以被用来当一个int使用。
class Date{
public:
static Month Jan() {return Month(1);}
static Month Feb() {return Month(2);}
...
static Month Dec() {return Month(12);}
private:
explicit Month(int m);
...
};
DAte d(Month::Mar(),Day(30),Year(1995));
Date
二、限制类型内什么可以做,什么不可以做
常见的限制时加上const。如,使用const修饰operater*返回值可阻止客户因自定义类型而犯错误。
if(a*b = c)
三、让你的types的行为与内置types一致
如,STL中的接口十分一致。每个STL容器都有一个名为size的成员函数。
四、使用std::tr1::shared_ptr可以避免诸多错误
- 函数返回值以shared_ptr代替裸指针,可以避免客户因忘记调用释放资源函数而导致的资源泄露(返回裸指针,通常要求调用者使用另一个接口释放资源)。使接口更易用。
- shared_ptr可以自定义删除器。可以将上述资源释放接口定义为删除器进而优化客户的调用逻辑。
- cross-Dll problem
对象在一个dll中new,在另一个dll中delete。使用shared_ptr的自定义删除器可以避免这个问题。
总结
- “促进正确使用”的办法包括接口的一致性,以及与内置类型的行为兼容。
- “阻止误用”的办法包括建立新类型、限制类型上的操作,束缚对象值,以及消除客户的资源管理责任。
- tr1::shared_ptr支持定制型删除器。这可防范DLL问题,可被用来自动解除互斥锁等等。