2011-04-02 107 views
1

編寫下面的代碼後:C++公共構造地址

#include <iostream> 

using namespace std; 
typedef struct Node { 
    int value; 

    Node(int index) { 
     value = index; 
    } 
} Node; 

int main() { 
    Node* arr[10]; 
    for(int i = 0; i < 10; i++) { 
     arr[i] = &Node(i); 
    } 
    for(int i = 0; i < 10; i++) 
     cout << arr[i]->value << endl; 
} 

我看到的代碼只打印9的,而不是所有的數字從0到9這是應該。 在調試代碼後,我看到每個i的arr [i]的地址都是相同的,並且Node(i)僅釋放了arr [i]的空間一次,之後只有value = index沒有釋放任何空間其他空間。爲什麼?

+1

在鍵盤上:http://codepad.org/boErRgnM它給出了'節點(i)'是臨時的警告。也許你應該堅持'新節點(i)' – quasiverse 2011-04-02 23:14:06

+0

我錯誤地寫了這個 – 2011-04-02 23:14:58

+2

後,我只是想知道避免問題的最好辦法是確保你的代碼編譯0警告。警告在技術上是有效的,但幾乎總是會導致問題的編程錯誤。您應該**始終**確保沒有警告(並儘可能高地轉動警告)。 – 2011-04-03 00:04:00

回答

6

此行:arr[i] = &Node(i);正在存儲指向臨時對象的指針。 Node(i)創建了一個臨時對象,可以在語句結束時將其析構,此時所有對它的引用都變爲無效,這意味着任何代碼的解除引用arr[i]的結果將是未定義的。在這種情況下,你得到所有9的原因是因爲編譯器正在優化代碼 - 因爲一次只創建1個臨時的Node(i),所以編譯器每次都通過循環重用該內存。

要解決該問題,請爲每個對象分配堆內存:arr[i] = new Node(i);。然後,當你使用的是他們做了你也將需要記住刪除每個之一:

for (int i=0; i < 10; ++i) { 
    delete arr[i]; 
} 

如果你想調查的更遠,嘗試加入一些代碼,您Node類,看看發生了什麼事:例如打印出來的地址this在你的構造函數中,和/或創建一個析構函數,只是打印一條消息,所以你可以看到它被調用。

+1

爲什麼我們動態分配節點對象?更好的解決方案是有一個Node對象數組而不是Node指針數組。 – 2011-04-02 23:50:19

+0

@Martin對於這個有限的代碼示例也是一種可能性(並且對於這個代碼示例來說更好,但是我會建議只是擺脫'Node'結構,只是打印1到10的數字),但是'Node '像這樣的結構通常用在樹或列表結構中,其中'Node'將被大量交換並且交換地址比實際結構快得多。 – user470379 2011-04-03 02:14:44

5

要創建新對象,請使用new Node(i)否則,您正在堆棧上創建臨時對象,這就是爲什麼它們都是相同的。

請記得在新的對象上調用delete。

+0

但爲什麼所有這些臨時對象都具有相同的地址? – 2011-04-02 23:17:07

+1

@The GiG只是巧合。編譯器恰好在這種情況下做到了這一點。 – quasiverse 2011-04-02 23:19:02

+1

@The GiG,每個對象在您獲取地址後立即銷燬。因此,該空間可用於下一個對象。因此它最終重新使用空間。你不能依賴那個,但那可能是這裏發生的事情。 – 2011-04-02 23:20:09

3
&Node(i) 

該表達式創建一個臨時變量並返回其地址。然後臨時銷燬,下次評估表達式時,在同一個地方創建另一個臨時地址 - 因此地址相同。

您應該可以避免使用指針,併爲Node引入默認值。

#include <iostream> 

using namespace std; 
typedef struct Node { 
    int value; 

    Node(int index) { 
     value = index; 
    } 

    Node() : value(0) {} // allow default construction 
} Node; 

int main() { 
    Node arr[10]; // default-construct array values 
    for(int i = 0; i < 10; i++) { 
     arr[i] = Node(i); 
    } 
    for(int i = 0; i < 10; i++) 
     cout << arr[i].value << endl; 
} 

請勿單獨爲每個對象使用new NodeAlways使用容器對象來管理一組具有相似語義的對象。如果你有,你可以在這裏使用std::vector,或者使用std::array。由std::vector引入的開銷將小於new引入的開銷。

+1

+1最佳答案。考慮到你應該在99%的時間內使用對象(特別是像Node這樣簡單的事情)。 – 2011-04-03 00:00:15