2010-07-28 79 views
0

我創建了一個A類和寫了下面的函數foo()內存分配混亂

class A 
{ 
public: 
int a; 
}; 

A * foo() 
{ 
A a1; 
return &a1; 
} 

int main() 
{ 
A * a2; 
a2 = foo(); 
return 0; 
} 

編譯器給了我一個警告,因爲A1是一個局部變量,我從堆棧中返回它的地址(因此它的價值可以改變不可預知)。

現在我改變foo的()以下

A * foo() 
{ 
A a1; 
A *a3; 
a3 = &a1; 
return a3; 
} 

現在,編譯器不給任何警告。這是因爲a3是在堆上創建的嗎?如果是這樣,指針總是像這樣在堆上創建。我認爲堆只能通過new/malloc來使用。

回答

4

現在編譯器不給出任何警告。

編譯器沒有給出任何警告,因爲你已經增加了足夠的複雜性來愚弄它對你的代碼的分析。

您仍然返回一個指向局部變量的指針,並且在該函數返回後您不能使用該指針。

+0

在堆棧或堆上是a3嗎? – Bruce 2010-07-28 21:50:33

+1

@Bruce:'a1'和'a3'都在堆棧中。當你從函數中返回指針'a3'的副本時,但是這對'a3'指向的對象沒有影響。 – 2010-07-28 21:52:18

1

您的代碼仍然無效。你的編譯器只是給出了非常糟糕的警告。

+0

從技術上講,只要沒有使用foo()的返回值,代碼就是有效的。 – 2010-07-28 22:01:47

1

不,這只是因爲編譯器不夠聰明才能理解a3指向堆棧上的a1。

你在做什麼仍然是未定義的。最好傳遞一個變量並將其設置爲:

void foo(A& a1) 
{ 
    a1.something = 1; 
    a1.somethingElse = 2; 
} 

或使用smart-pointers

+0

在堆棧上是a3嗎? – Bruce 2010-07-28 21:48:50

+0

@Bruce:a3在堆棧中,但它的VALUE是一個內存地址。這個內存地址可以通過值返回,就像int一樣,這就是爲什麼'return a3;'如果a3指向非臨時的東西,這將是有效的。但是,現在的內存地址是堆棧中的地址,當函數返回時會釋放該地址;這就是爲什麼該內存地址不是有效的返回值(返回它是未定義的行爲) – 2010-07-28 21:50:32

+0

_Returning_指向一個函數的指針指向一個局部變量不會導致未定義的行爲。 _使用這樣一個指針呢。兩者之間有一個微妙而重要的區別。 – 2010-07-28 21:54:34

1

編譯器只查看一個間接級別的警告 - 第二個例子與第一個例子一樣危險。

1

您仍然返回在堆棧中分配的項目的地址(所以它仍然是錯誤的)。但是因爲您添加了另一個間接層,您已阻止編譯器檢測並警告您。