簡體   English   中英

檢測 C++ 中不安全的常量引用綁定

[英]Detecting unsafe const reference binding in C++

我剛剛花了很多時間在我的一個程序中調試一個模糊的內存損壞問題。 它本質上歸結為一個函數,該函數通過以將其傳遞給對象構造函數的方式調用的值返回一個結構。 偽代碼如下。

extern SomeStructure someStructureGenerator();

class ObjectWhichUsesStructure {
  ObjectWhichUsesStructure(const SomeStructure& ref): s(ref) {}
  const SomeStructure& s;
}

ObjectWhichUsesStructure obj(someStructureGenerator());

我的理由是: someStructureGenerator()正在返回一個臨時的; this 被綁定到一個 const 引用,這意味着編譯器正在延長臨時文件的生命周期以匹配使用位置; 我用它來構造一個對象,所以臨時生命周期被延長以匹配對象的生命周期。

事實證明,最后一點並非如此。 一旦構造函數退出,編譯器就會刪除臨時obj ,現在obj包含對超空間的引用,當我嘗試使用它時,結果很有趣。 我需要將 const 引用顯式綁定到作用域,如下所示:

const auto& ref = someStructureGenerator();
ObjectWhichUsesStructure obj(ref);

這不是我要問的問題。

我要問的是:我的編譯器是 gcc 8,我用-Wall構建,並且很高興編譯上面的代碼 --- 干凈利落,沒有警告。 我的程序在 valgrind 下愉快地(但錯誤地)運行,同樣沒有警告。

我不知道我的代碼中有多少其他地方使用了相同的習語。 什么編譯器工具會檢測並標記這些地方,以便我可以修復我的代碼,並在我將來犯同樣的錯誤時提醒我?

首先,引用綁定在這里確實“延長了生命周期”——但僅限於構造函數參數的生命周期(無論如何都不會長於臨時物化的生命周期)。 s(ref)沒有綁定一個對象(因為ref已經是一個引用),所以不會發生進一步的擴展。

因此,可以通過聚合初始化執行您期望的擴展:

struct ObjectWhichUsesStructure {
  const SomeStructure &s;
};

ObjectWhichUsesStructure obj{someStructureGenerator()};

這里沒有構造函數參數(因為根本沒有構造函數!)所以只有一個,期望的綁定發生。

值得一看的是,編譯器為什么不對此發出警告:即使構造函數確實保留了對臨時參數的引用,也有合法的情況下它起作用:

void useWrapper(ObjectWhichUsesStructure);
void f() {useWrapper(someStructureGenerator());}

在這里, SomeStructure住到語句,在此期間結束useWrapper可以善用在參考的ObjectWhichUsesStructure

禁止上述有效用例為代價,您可以通過提供一個帶右值引用的已刪除構造函數來讓編譯器捕獲有問題的情況:

struct ObjectWhichUsesStructure {
  ObjectWhichUsesStructure(const SomeStructure& ref): s(ref) {}
  ObjectWhichUsesStructure(SomeStructure&&)=delete;
  const SomeStructure& s;
};

這可能值得暫時作為一種診斷措施而不是永久限制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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