2010-01-13 62 views
0

即使函數返回的值是該函數的局部變量,是否可以返回const引用?我知道當函數返回時,局部變量不再有效 - 但是如果函數被內聯並且返回的值僅在調用者範圍內使用,該怎麼辦?那麼函數的本地應該被包含在調用者堆棧中,不是嗎?C++返回本地變量的const引用

回答

8

不要指望它。即使這對一個編譯器有效,它也不是標準支持的行爲,並且很可能在其他編譯器上打破。

0

當被調用者超出範圍時,該值超出範圍。所以不,它消失了。

但是,如果你想有一個相當醜陋的解決方案(和紅旗警告你,你的設計可能需要重構),你可以做這樣的事情:

const MyObj& GetObj() 
{ 
    static const MyObj obj_; 
    return obj_; 
} 

...但這種解決方案是否充滿危險,特別是如果對象是可修改的,或者在多線程環境中做一些不平凡的事情。

+0

對於不可修改的對象,這實際上並不是一個不好的解決方案。 – 2010-01-13 15:43:05

+0

如果它們是不可變的,它們可以在外部範圍內聲明,並且不需要實際返回它們。 – 2010-01-13 15:45:38

4

inline保證 - 這是一個建議。即使您使用技巧強制內聯,您也永遠無法確定結果,特別是如果您想保持便攜性。因此,不要做到這一點。

0

inline關鍵字不保證該函數是真正內聯的。不要這樣做。

5

不,它不好。局部變量在堆棧中聲明,堆棧在方法調用之間不斷變化。而且,超出範圍的對象也會被銷燬。總是返回一個局部變量的副本。

考慮以下代碼:

#include <iostream> 
using namespace std; 

class MyClass 
{ 
public: 
    MyClass() { cout << "ctor" << endl; } 
    ~MyClass() { cout << "dtor" << endl; } 
    MyClass(const MyClass& r) { cout << "copy" << endl; } 
}; 

const MyClass& Test() 
{ 
    MyClass m; 
    return m; 
} 

int main() 
{ 
    cout << "before Test" << endl; 
    MyClass m = Test(); 
    cout << "after Test" << endl; 
} 

這將打印出:

before Test 
ctor 
dtor 
copy 
after Test 
dtor 

你要複製的對象已經要求其析構函數,並且可以處於無效狀態。

1

這樣做會調用未定義的行爲。

  • 有沒有辦法強制編譯器內聯函數。 inline只是一個建議 - 也是如此__forceinline
  • 即使你可以保證該函數將被內聯,所討論變量的析構函數仍然會被執行,留給你一個對死對象的引用。
  • 而大的 - C++的堆棧概念是由作用域劃分的 - 而不是按功能劃分的。

#include <iostream> 
int main() 
{ 
    { 
    int a = 5; 
    std::cout << std::hex << "0x" << &a << std::endl; 
    } 
    { 
    int b = 10; 
    std::cout << std::hex << "0x" << &b << std::endl; 
    } 
} 

我的編譯器放 'A' 和 'B' 在不同的內存地址。 除開啓優化之外。你可能會認爲這是一個優化重用你的對象以前佔用的內存。

你在這裏試圖解決一個問題嗎?如果這是您的擔憂,還有其他方法可以減少創建的臨時對象的數量。

+0

你還記得你究竟在哪裏學習C++堆棧是由範圍分隔的嗎? – 2010-01-13 15:58:48

+0

不可以。但是析構函數調用發生在範圍邊界上,而不是函數邊界,所以看起來很明顯。 – 2010-01-13 16:00:24

+0

不是。析構函數在範圍邊界上被調用,但這並不意味着堆棧在該邊界上被捲起或展開。我只是看了一個簡單的應用程序,它有兩個嵌套在另一個範圍內的應用程序,並且看到棧指針沒有任何反應。試過版本和調試版本。那麼,我想正確的答案是 - 它是編譯器特定的。 – 2010-01-13 16:05:14

1

正如其他人所指出的,這是危險的。如果您的編譯器支持NRVO(命名返回值優化),並且您的函數使用並返回您本來希望以ref以相當簡單的方式返回的局部變量,那也沒有必要。

NRVO允許編譯器在特定條件下避免複製構造 - 通常是避免按值返回對象的主要原因。 VC++ 8支持這個(在以前的修訂版上是一個增量),並且它在經常使用的代碼中有相當多的性能差異。