今天,翻看了一下上大學時寫的一些練習代碼。看到了以下一段C代碼:
float sum(float a[], unsigned length)
{
int i;
float result = 0.0f;
for(i = 0; i<=length-1; i++)
result += a[i];
return result;
}
這段c code雖說能編譯通過,但是,在length接受為0時,發生存儲越界,而不是期望中的0.0f。
歸咎原因,可以說是“i<=length-1”上發生的類型轉換造成的,當然,這是從語言的角度來看待這個問題的。
更為本質的問題是,沒有對length作范圍檢查!所以,更應該說是programmer的素質問題。
好,從中可以知道:
1 c的內部類型轉換是混亂的.也就是在對待unsigned length和int length上的問題.
2 依賴于c的類型轉換是危險的.
3 對于int和unsigned這樣類型的值,有時需要類型檢查,而這一步沒有語言的直接支持.
對于1和2,只有靠自身的修為;對待3,在C語言里最多可以寫個簡單的宏或inline函數,比如:
inline int rangeCheck(unsigned n, unsigned lower, unsigned upper)
{
if( nupper)
return 0;
else
return 1;
}
這樣的代碼當然有許多缺陷.
到了c++也存在著這樣的問題,看下面的:
templateclass Stack{
public:
Stack(unsigned size);
// others
};
//...
Stack s1(9); // OK!
Stack s2(0); // ??
Stack s3(-4); // ??
于是可能會想把constractor改成"Stack(int size);".
這么做意味著Stack模板類的不變性的一部分由用戶負責,于是在這個類的文檔中會有一些特別說明.這樣做不見的有多好.
開動腦筋之后,于是有:
templateinline void Assert(Expression assertion)
{
if(!assertion)
throw Except();
}
// 范圍(low, high)
templateclass Range
{
struct Error{};
int val;
void Check(int i)
{
Assert(low <= i && i <= high);
}
public:
class Error{};
Range(int i)
{
Check(i);
val=i;
}
operator int () { return val; }
operator int () const { return val; }
};
然后,再寫Stack的實現就成了:
#include
templateclass Stack{
public:
Stack(Range<0,numeric_limits::max() > size);
// others
};
// user code
Stack s1(9); // OK!
Stack s2(0); // occur exception
Stack s3(-4); // occur exception
這么做實在太好了,用戶代碼的結構清晰.Stan Lippman也有過一篇文章論述過以上問題.