V595診斷邏輯很簡單。如果在開始時解除引用指針,則會發出警告,然後驗證其是否等於nullptr。
當然,有很多情況下分析儀會很安靜,遇到了這樣的模式。包括指針不等於nullptr時的情況,因此分析器將保持安靜。然而,Q_ASSERT(_parent)
不保證指針_parent
非零。如果_parent
爲零,則Q_ASSERT語句將使用qFatal函數輸出以下消息。如果您使用默認消息處理程序,則此函數將中止以創建核心轉儲。
您可以安裝您自己的處理程序,它將繼續運行該程序。所以理論上分析儀是正確的。可能會發生空指針的潛在取消引用。
我們不是理論家,而是實踐,我們認識到這段代碼應該被認爲是正確的。分析儀不熟悉此類代碼視圖,其中尚未使用宏Q_ASSERT
。我們將修改分析器,以便它開始將這些代碼模式視爲正確。即在未來的分析會認爲這裏:永遠不會執行
Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount());
_parent->childCount()
函數調用,如果指針_parent
等於nullptr。如果指針爲空,則由於調用qFatal()
,程序將提前停止工作。
當然,正如我上面已經說過的,您可以更改處理程序的行爲,並且不會導致中止程序。但是,在實踐中,沒有人會改變處理程序並編寫我們在此考慮的代碼。
這可能是答案的終點。所以,我們會改進分析儀,就是這樣。但是,不可能預見所有可能的選擇。如果是我們自己的宏,如何抑制一個警告?
假設這個自制錯誤記錄系統和分析儀對自定義函數Foo()
一無所知。
void Foo(bool expr);
#define Q_ASSERT(expr) Foo(expr);
inline T *sibling(int row) const
{
Q_ASSERT(_parent);
Q_ASSERT(row < _parent->childCount())
return _parent ? _parent->child(row) : nullptr;
}
最簡單的,但不是最好的辦法就是明確標示警告爲假時使用註釋:
Q_ASSERT(row < _parent->childCount()) //-V595
另一種選擇是改變編寫代碼的風格,寫如下:
inline T *sibling(int row) const
{
if (_parent == nullptr)
{
Q_ASSERT(false);
return nullptr;
}
Q_ASSERT(row < _parent->childCount());
return _parent->child(row);
}
對於這樣的代碼,分析儀不會發出警告V595,因爲沒有理由這樣做。代碼變得更長一點,但在我看來,它現在更符合邏輯正確和安全。我推薦這種處理這種警告的方式。
最後是在宏中使用警告抑制機制。要在宏定義的頭文件中執行此操作,您應該寫一條註釋:
//-V:Q_ASSERT:595
此警告消失後。當然,並不總是可以更改聲明宏的文件。然後,您可以使用其中一個全局文件。在Visual C++項目中,一個好的候選項是stdafx.h。另一種選擇是使用診斷配置文件(pvsconfig)。所有這些方法在「Suppression of false alarms」部分的文檔中有詳細描述。 markup base也存在。
它是否與assert()一起工作?我記得LLVM的靜態分析器也與Q_ASSERT –
混淆assert()相同。 –
如果:'return _parent!= nullptr? _parent-> child(row):nullptr;'? – AlexanderVX