簡體   English   中英

是否有C ++警告將引用返回臨時?

[英]Is there a C++ warning for returning a reference into a temporary?

這種情況有一個錯誤:

const int& foo() {
    const int x = 0;
    return x;
}

乃至

const int& foo() {
    const std::pair<int,int> x = {0,0};
    return x.first;
}

但不是這個:

const int& foo() {
    const std::array<int,1> x = {0};
    return x[0];
}

(不太令人驚訝)不是這樣的:

const int& foo() {
    const std::vector<int> x = {0};
    return x[0];
}

特別是在std::vector情況下,我得到這個警告會非常棘手,因為編譯器並不明顯std::vector<int>::operator[](size_t) const返回的const int&是一個引用到臨時。 我實際上有點驚訝std::array沒有失敗,因為這個類似的情況確實給了我一個錯誤:

struct X {
    int x[0];
};

const int& foo() {
    X x;
    return x.x[0];
}

任何流行的編譯器都有警告/錯誤可以捕獲這些情況嗎? 我可以想象一個保守的版本會警告返回來自臨時成員函數調用的引用。

我用以下內容絆倒了這個,其中我內聯了一系列鏈接調用,但是因為C ++允許你將locals分配給const& ,所以詳細版本可以工作,而表面上相同的版本會立即刪除臨時版本,留下懸空參考:

#include <iostream>

struct A {
    int x = 1234;
    A() { std::cout << "A::A " << this << std::endl; }
    ~A() { x = -1; std::cout << "A::~A " << this << std::endl; }
    const int& get() const { return x; }
};

struct C { 
    C() { std::cout << "C::C " << this << std::endl; }
    ~C() { std::cout << "C::~C " << this << std::endl; }
    A a() { return A(); }
};

int foo() {
    C c;
    const auto& a = c.a();
    const auto& x = a.get();
    std::cout << "c.a(); a.get() returning at " << &x << std::endl;
    return x;
}

int bar() {
    C c;
    const int& x = c.a().get();
    std::cout << "c.a().get() returning at " << &x << std::endl;
    return x;
}

int main() {
    std::cout << foo() << std::endl;
    std::cout << bar() << std::endl;
}

那輸出

C::C 0x7ffeeef2cb68
A::A 0x7ffeeef2cb58
c.a(); a.get() returning at 0x7ffeeef2cb58
A::~A 0x7ffeeef2cb58
C::~C 0x7ffeeef2cb68
1234
C::C 0x7ffeeef2cb68
A::A 0x7ffeeef2cb58
A::~A 0x7ffeeef2cb58
c.a().get() returning at 0x7ffeeef2cb58
C::~C 0x7ffeeef2cb68
-1

詳細版本可以正常工作,而表面相同的版本會立即刪除臨時版本,留下懸空參考

您的代碼完全不相同。 在第一種情況:

const auto& a = c.a();
const auto& x = a.get();

臨時擴展的生命周期為const引用的生命周期,因此只要a有效, x就有效,但在第二個:

const int& x = c.a().get();

你有懸掛參考x 你在這里的情況與你之前顯示的例子無關 - 當你返回一個對本地變量的懸空引用時,因此警告你正在查看幾乎不相關的例子,如果編譯器會檢測到你在實際代碼中描述的情況。

雖然可以由A類設計師為您的案例解決方案:

struct A {
    int x = 1234;
    A() { std::cout << "A::A " << this << std::endl; }
    ~A() { x = -1; std::cout << "A::~A " << this << std::endl; }
    const int& get() const & { return x; }
    int get() && { return x; } // prevent dangling reference or delete it to prevent compilation
};

使用壽命已結束的值是未定義的行為,請參閱[basic.life] /6.1 該標准不要求編譯器輸出任何 UB診斷。

因此,您所看到的診斷只是對編譯器的禮貌。 很高興看到你得到了其中的一些,但是你注意到它們肯定遠非防水。

是的,終身延伸不可鏈接。 這使得它非常危險和不可靠。

您可以嘗試Clang的Address Sanitizer(ASAN)。

事實上,ASAN似乎正在捕捉你的問題( -fsanitize-address-use-after-scope ):

==35463==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fffffffe970 at pc 0x000000498d53 bp 0x7fffffffe910 sp 0x7fffffffe908
READ of size 4 at 0x7fffffffe970 thread T0

暫無
暫無

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

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