2011-07-16 51 views
1

我想到了一個奇怪的C++作弊。通常情況下,我不能從範圍走私引用,因爲我無法在包含範圍中定義未初始化的引用。但是,我可以定義一個指向包含引用的類的指針,無法初始化它,然後將它分配給一些初始化爲局部變量的動態內存的地址。即使該動態對象包含對超出範圍的變量的引用,指向對象仍然具有相同值的有效引用!即使我告訴它是-pedantic,g ++也不會抱怨,所以我認爲它是有效的。但是,如何,爲什麼?模仿「指向引用的指針」的類可以保存作用域變量嗎?

struct int_ref 
{ 
    int &x; 
    int_ref(int &i): x(i) {} 
}; 

#include <iostream> 
using namespace std; 

int main(void) 
{ 
    int_ref *irp; 
    int i = 1; 
    int_ref a(i); // Creates an int_ref initialized to i 
    irp = &a; // irp is now a pointer to a reference! 
    // Prints 1 
    cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl; 
    i = 2; 
    // Prints 2 
    cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl; 
    int j = 3; 
    int_ref b(j); 
    irp = &b; 
    // Prints 3 
    cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl; 
    i = 1; 
    // Still prints 3 
    cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl; 
    { 
    int k = 4; 
    irp = new int_ref(k); 
    // k goes out of scope 
    } 
    int k = 1; // Doesn't affect the other k, of course 
    // Prints 4 ?! 
    cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl; 
} 

編輯:這實際上可以是(如在答案建議的)未確診的懸空參考。那麼如果我定義int_ref這樣的:

struct int_ref 
{ 
    const int &x; 
    int_ref(const int &i): x(i) {} 
}; 

一個const引用不必引用到左值,所以沒有明確的一個叼着一個概念。代碼仍未定義?

回答

3

僅僅因爲你的編譯器沒有爲你的程序發出診斷信息並不意味着你的程序是好的,有效的和安全的。

由於您有一個懸掛參考,因此您的最後一行將調用未定義的行爲。這不需要編譯器進行診斷,但它也沒有做到正確。你可能會得到4仍然在內存中),你可以得到一些其他的值,你可能會得到一個分段錯誤,或者你的電腦可能爆炸。

只是不這樣做。


術語記:有沒有「指針引用」(沒有這樣的事情存在)在這裏,只有一個指向int_ref

+0

這就是爲什麼他說**模仿**參考指針:) –

+0

@Armen:他的代碼有一個評論說:「irp現在是指向參考的指針! :) –

+0

感謝您的回答。我提出了一個關於這個問題的變種。你能看看底部的新段落嗎? (另外,重申:評論:我想我是過火的人,正如我所說,它只是模仿一個)。 –

4

你做了什麼有undefined behavior

{ 
    int k = 4; 
    irp = new int_ref(k); 
    // k goes out of scope 
    } 
    int k = 1; // Doesn't affect the other k, of course 
    // Prints 4 ?! ***it could print 42 - no guarantees*** 
    cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl; 

您正在保留(和使用)對超出範圍的對象的引用。無論您如何間接保留該參考,它都是未定義的行爲。

未定義行爲的最壞表現是似乎行得通。在這種情況下,你有錯誤的安全感,但鼻子守護進程可能會飛到所有的地方,相信我;)

至於爲什麼即使在迂迴模式下編譯器也不抱怨,那麼很難做到這種代碼的靜態分析來檢測這些事情。所以它留給你自己的關注。

+0

有一個案例可以爲事實上,由於我們人類幾乎可以立即看到這是UB,因此編譯器應該能夠做到。當然,真正的原因是UB不需要被診斷。 –

+0

@Tomalak:一個好的編譯器可以完成許多不符合標準的事情。我認爲真正的原因在於它不是那麼微不足道的 –

+0

好,夠公平的。 –

相關問題