今天,翻看了一下上大學(xué)時(shí)寫的一些練習(xí)代碼。看到了以下一段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時(shí),發(fā)生存儲(chǔ)越界,而不是期望中的0.0f。
歸咎原因,可以說是“i<=length-1”上發(fā)生的類型轉(zhuǎn)換造成的,當(dāng)然,這是從語言的角度來看待這個(gè)問題的。
更為本質(zhì)的問題是,沒有對(duì)length作范圍檢查!所以,更應(yīng)該說是programmer的素質(zhì)問題。
好,從中可以知道:
1 c的內(nèi)部類型轉(zhuǎn)換是混亂的.也就是在對(duì)待unsigned length和int length上的問題.
2 依賴于c的類型轉(zhuǎn)換是危險(xiǎn)的.
3 對(duì)于int和unsigned這樣類型的值,有時(shí)需要類型檢查,而這一步?jīng)]有語言的直接支持.
對(duì)于1和2,只有靠自身的修為;對(duì)待3,在C語言里最多可以寫個(gè)簡(jiǎn)單的宏或inline函數(shù),比如:
inline int rangeCheck(unsigned n, unsigned lower, unsigned upper)
{
if( nupper)
return 0;
else
return 1;
}
這樣的代碼當(dāng)然有許多缺陷.
到了c++也存在著這樣的問題,看下面的:
templateclass Stack{
public:
Stack(unsigned size);
// others
};
//...
Stack s1(9); // OK!
Stack s2(0); // ??
Stack s3(-4); // ??
于是可能會(huì)想把constractor改成"Stack(int size);".
這么做意味著Stack模板類的不變性的一部分由用戶負(fù)責(zé),于是在這個(gè)類的文檔中會(huì)有一些特別說明.這樣做不見的有多好.
開動(dòng)腦筋之后,于是有:
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的實(shí)現(xiàn)就成了:
#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
這么做實(shí)在太好了,用戶代碼的結(jié)構(gòu)清晰.Stan Lippman也有過一篇文章論述過以上問題.