[英]Safe pointer dereferencing in C++
在我們的代碼庫中,我們有許多類似以下的構造:
auto* pObj = getObjectThatMayVeryRarelyBeNull();
if (!pObj) throw std::runtime_error("Ooops!");
// Use pObj->(...)
在99.99%的情況下,不會觸發此檢查。 我正在考慮以下解決方案:
auto& obj = deref_or_throw(getObjectThatMayVeryRarelyBeNull());
// Use obj.(...)
其中deref_or_throw
聲明如下:
template<class T> T& deref_or_throw(T* p) {
if (p == nullptr) { throw std::invalid_argument("Argument is null!"); }
return *p;
}
該代碼更加清晰,可以根據需要運行。
問題是:我是否正在重新發明輪子? 標准或增強中是否有相關解決方案? 或者您對解決方案有何評論?
PS。 相關問題(答案不令人滿意): 是否有C ++等效於NullPointerException
有兩種方法可以處理“空指針的罕見情況”問題。 首先,它是建議的異常解決方案。 為此,方法deref_or_throw
是一件好事,盡管我寧願拋出runtime_error
,而不是invalid_argument
異常。 如果您願意,也可以考慮將其命名為NullPointerException
。
但是,如果ptr != nullptr
情況實際上是該算法的前提條件,則應盡最大努力使該非null情況達到100%的安全性。 在這種情況下, assert
是適當的事情。
assert
優點:
assert
缺點:
您還應該考慮編寫一種方法getObjectThatMayNeverBeNullButDoingTheSameAsGetObjectThatMayVeryRarelyBeNull()
:該方法保證可以返回指向對象的非null指針,否則該指針與原始方法完全等效。 但是,如果可以加倍努力,我強烈建議無論如何不要返回原始指針。 擁抱C ++ 11並按值返回對象:-)
您可以並且可能應該在設計時考慮到null
例。 例如,在您的問題域中,類方法何時返回null
才有意義? 什么時候使用null
參數調用函數有意義?
廣義上講,只要有可能,從代碼中刪除null
引用都是有益的。 換句話說,您可以對不變量進行編程,使其“此處或此處都不為空”。 這有很多好處。 您無需通過將方法包裝在deref_or_throw
來混淆代碼。 您可能會從代碼中獲得更多的語義含義,因為在現實世界中事物多長時間為null
? 如果您使用異常來表示錯誤而不是null
值,則代碼可能更具可讀性。 最后,您減少了錯誤檢查的需要,並降低了運行時錯誤(可怕的空指針取消引用)的風險。
如果您的系統在設計時沒有考慮到null
情況,那么我想說最好deref_or_throw
, 不要用deref_or_throw
瘋狂地包裝所有deref_or_throw
。 也許采取敏捷方法。 在編寫代碼時,請檢查您的類對象作為服務提供的合同。 可以合理預期這些合同多久返回一次null
? 在這些情況下null
的語義值是什么?
您可能會確定系統中可能合理預期返回null
。 對於這些類, null
可能是有效的業務邏輯,而不是指示實現錯誤的邊緣情況。 對於可能期望返回null
,額外的檢查可能是值得的。 從這個意義上講,檢查null
更像是業務邏輯,而不是底層實現細節。 但是,將所有指針deref_or_throw
系統地包裝在deref_or_throw
可能是一種解決方法,這本身就是毒葯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.