簡體   English   中英

C ++中的安全指針解引用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM