解決項目的問題,意識到斷言的重要性。如果一個程序在某處遇到了非法的值,那么最好的情況便是在此刻停下報錯,最壞的情況便是程序不吭不響的執(zhí)行著~~直到你發(fā)現(xiàn)他執(zhí)行的方式極為詭異,此時,你要花九牛二虎之力才能找到錯誤所在之處~~~~
學習一下斷言吧:
·······什么是斷言
在某處判斷某一個表達式的值為真或者假,如果假則輸出錯誤消息并停止程序的執(zhí)行~
assert是宏,而不是函數(shù),只在debug版本中有效,因此無需在release版本刪除。
·······哪幾種斷言
MFC
ASSERT
void foo(char* p,int size)
{
ASSERT(p != 0); // 驗證緩沖區(qū)指針
ASSERT((size >= 100); // 確認緩沖區(qū)大小至少為100字節(jié)
// foo 函數(shù)的其它計算過程
}
如果沒有定義_DEBUG預處理符,則該語句不會真正生成代碼。Visual C++會在調(diào)試模式編譯時自動定義_DEBUG,而在發(fā)行模式下,該預處理符是不存在的。如果定義了_DEBUG,則上述兩個斷言生成的代碼類如:
//ASSERT(p != 0);
do
{
if(!(p != 0) && AfxAssertFailedLine(__FILE__, __LINE__))
AfxDebugBreak();
} while(0);
//ASSERT((size >= 100);
do
{
if(!(size >= 100) && AfxAssertFailedLine(__FILE__,__LINE__))
AfxDebugBreak();
}while(0);
ASSERT_KINDOF(classname,pObject); ASSERT_KINDOF(CDocument,pDocument);
檢驗pObject指向的對象是classname類的一個對象或者其派生類的對象
ASSERT_VALID(pObject); pObject 必須是一個派生于CObject類的類對象,會調(diào)用其重寫的AssertValid函數(shù) ,例如
如果使用應用向導或類向導生成基于MFC的類,通常會得到AssertValid()的骨架,最好改寫這些骨架代碼以增加最基本的完整性檢查。下面是一個典型的例子,類Sample從CObject繼承,假定它含有職員名字及其薪水:
class Sample : public CObject
{
protected:
CString m_Name; // 職員名字
double m_Salary; // 薪水
public:
Sample(LPCTSTR name,double salary) : m_Name(name), m_Salary(salary) {}
#ifdef _DEBUG
virtual void AssertValid() const;
#endif
};
#ifdef _DEBUG
void Sample::AssertValid() const
{
CObject::AssertValid(); // 驗證基類
ASSERT(!m_Name.IsEmpty()); // 驗證職員名字
ASSERT(m_Salary > 0); // 驗證薪水
}
#endif
CRT assertion
_ASSERT 和 _ASSERTE 后一個會在出錯時同時打印出條件判斷句
ANSI
assert()
注意:assert用于檢測非法的輸入,但是合法的輸入并不一定是正確的,例如:
int pB = (int*)malloc(sizeof(int)*1000);
assert(pB!=NULL) //錯誤的使用assert 他會在release版本失效~也就是說assert不應該對程序產(chǎn)生副作用
正確的做法:
int pB = (int*) malloc(sizeof(int)*1000);
if(pB == NULL)
{
//錯誤處理
}
else{
}
另一個例子:
void draw(){
CFigure* pF = getCF();
assert(pf!=NULL);
if(pf == NULL){}
else{
}
}
此處,對于getCF來說返回值為NULL是非法的,如果他的返回值可能為null就沒必要加上assert語句。
而下面的if語句則是為了防止release版本出現(xiàn)null指針的情況。
VERIFY()
由于ASSERT僅在程序的調(diào)試版起作用,測試表達式總是被動的。也就是說,它們不能包含賦值、增量、減量等真正改變數(shù)據(jù)的操作。但有時候我們需要驗證一個主動表達式,比如賦值語句。這時可以使用VERIFY代替ASSERT。下面是一個例子:
void foo(char* p,int size)
{
char* q; // 指針的副本
VERIFY(q = p); // 拷貝指針并執(zhí)行驗證
ASSERT((size >= 100); // 確保緩沖區(qū)大小至少為100字節(jié)
// 執(zhí)行 foo 的其它操作
}
在調(diào)試模式下ASSERT和VERIFY是相同的。但在release模式下,VERIFY能夠繼續(xù)對表達式求值(但不再進行斷言檢驗),而ASSERT語句在效果上就如同已經(jīng)刪除了一樣。
盡管在MFC源代碼中可以找到一些應用VERIFY的例子,但ASSERT用得更為普遍。一些程序員總是完全避免使用VERIFY,因為他們已經(jīng)習慣于使用被動斷言。請記住,如果在ASSERT語句中使用了主動表達式,編譯器不會發(fā)出任何警告。在發(fā)行模式下編譯時該表達式會被直接刪除,從而導致程序運行的錯誤。由于發(fā)行版程序不含調(diào)試信息,這種類型的錯誤是很難找到原因的。