2013-04-18 46 views
3

例如在這兩個代碼中,一個不需要指針,另一個不需要指針。爲什麼是這樣?如果myObject1不是指針,那麼究竟是什麼?爲什麼需要在堆上初始化一個對象而不是在堆棧上的指針?

class Object{ 
… 
}; 


int main(){ 
    // Create instance on the stack 
    Object myObject1; 

    // Create instance on the heap 
    Object *myObject2 = new Object; 

    return 0; 
} 

感謝您的幫助。

+6

指針不*需要*,只是記住的一種便捷方式,其中對象是。只用'new Object'也會在堆上創建一個對象,但是我們不知道它在哪裏。 –

回答

1

例如在這兩個代碼中,一個不需要指針,另一個不需要指針,其他的 。爲什麼是這樣?

因爲你是以一種(無保證的)嘗試匹配你上面寫的評論的方式寫的。

如果myObject1不是指針,那究竟是什麼?

Object。即,類型爲Object的對象。也就是Object類的一個實例。

+0

'myObject2'也是一個對象,它是一個指向Object類型對象的指針。 –

+0

@AlexeyFrunze是的。我從不否認這一點。 myObject2是Object *類型的對象,myObject1是Object類型的對象。 –

4

這是一個實例(或一個對象)的類。 myObject2到一個類的實例。

你可以有一個指針指向的變量在堆棧上還有:

int main() 
{ 
    Object myObject1; 
    Object* pointerToObjectOnStack = &myObject1; 
} 

指針可能指向任何地方;堆棧,堆或全局變量(它既不在堆棧中也不在堆中)。

1

myObject1是分配在堆棧中的Object

Here你會找到更準確的內存信息。

在兩個字:

  1. 所有的局部變量(包括對象實例)上的功能被在堆棧分配。
  2. 所有動態分配(使用newmalloc())數據分配在
7

您的兩個聲明都是具有自動存儲持續時間的對象的定義。也就是說,它們都將在函數結束時被銷燬。第一個是聲明Object類型對象,第二個是Object*類型對象。

剛剛發生的myObject2的初始值爲新表達式。一個新的表達式動態分配一個對象並返回一個指向它的指針。 myObject2正在使用指向動態分配的Object的指針進行初始化。

因此,您正在見證創建對象的兩種不同方式。一個是可變定義,另一個是新表達式

它沒有任何其他意義。想象一下,新表達式沒有返回指向對象的指針,而是直接引用該對象。然後,您可能會這樣寫:

Object myObject2 = new Object(); 

但是,C++默認使用值語義。這意味着動態分配的對象將被複制到myObject2,然後你失去了它的跟蹤。您無法再獲取該對象的地址。 A 新表達式返回一個指針,以便您擁有動態分配的對象的句柄。

你可能會說:「好吧,我就是這麼寫的!但那是因爲Java以不同的方式工作。在Java中,myObject2是您設置爲指向新的Object對象的參考。它不會以任何方式複製對象。

C++並不要求您在動態分配對象時必須使用指針。事實上,你可以做這樣的事情(這是一種在Java當量):

Object& myObject2 = *(new Object()); 

但是,這是一個非常糟糕的主意。它突然掩蓋了對象被動態分配的事實,並且很容易犯一個錯誤並忘記銷燬對象(在Java中你不必關心)。至少有一個指針可能會提醒你這樣做。但是,即使這樣會導致錯誤或不清晰的代碼,這就是爲什麼建議您儘可能使用智能指針的原因。

簡而言之:這就是新表達式的行爲方式。它動態分配一個對象,然後返回一個指向它的指針。

1

當你在堆棧中分配一個對象時,編譯器會爲你做所有的髒處理(分配/處理),所以你不需要一個指針來使用這個對象。當你引用myObject1時,你指的是Object本身,你可以簡單地訪問它的字段,方法等等。

請注意,您始終可以通過使用&運算符獲取堆棧變量的指針。

Object myObject1; // This is the live instance of Object 
Object * pObject1 = &myObject1; // Here you can obtain a pointer 
           // to myObject1 
myObject1.someField = 42;  // Accessing myObject1's data 

在另一方面,在堆上分配對象要求管理這些對象(分配/手動他們使用新/刪除的malloc /自由等解除分配),所以首先你得到的指針內存,對象所在的位置並使用它,則必須使用*運算符對其進行取消引用。

Object * myObject1 = new Object(); // Here you construct the Object manually 
            // and get the pointer to place, where Object 
            // was allocated. 
(*myObject1).someField = 42;  // Accessing myObject1's data, notice the 
            // dereference (*) 
myObject1->someField = 42;   // The same, written more easily 
-3

如果在堆棧上分配變量,編譯器將爲您隱式生成一個指針。

Object myObject1; myObject1.foo(); 將被編譯爲

Object* myObject1_implicit_ptr = new(alloca(sizeof(Object))) Object; 
myObject1_implicit_ptr->foo(); 

alloca分配堆棧存儲器)


Object myObject1;myObject1是其中對象的實例駐留存儲器位置的名稱,即它的地址別名(相對於堆棧幀指針)。
我們可以查詢該地址與operator&和存儲到一個指針(它擁有一個地址的變量):

Object myObject1; // myObject1 == stack-frame-pointer + 123 
Object* myObject1_ptr = &myObject1; 
+1

如果你問我,這比澄清更令人困惑。雖然在技術上它是等價的,但我很難證明編譯器「實際上」做的比其他任何事情都重要。 –

+3

儘管這可能反映了它如何編譯爲機器代碼,但是在內存中使用'alloca'放置'new'肯定不會以任何方式理解OP的問題的實際概念,並且可能會更糟糕比好。 –

+0

@MagnusHoff那麼,在大會上它可能確實會有相似的效果。爲堆棧中的對象分配內存,並使用指向該內存的指針調用每個成員函數。但我完全同意這並不能真正幫助任何人。 –

0

每個對象,它是一個功能的一部分在堆棧上分配時該函數隨着稱爲一些元數據。這個元數據結構是在編譯器編譯函數時定義的 - >這會導致從函數快速訪問這些變量(相對位置不會改變)。這個內存在函數返回時總是(自動)釋放。

雖然堆設置在內存的不同部分,可以或不可以根據邏輯使用。

有一件事你有一個錯誤,它會很容易通過拆分您的代碼顯示兩行:

class Object{ 
… 
}; 

int main(){ 
    // Create instance of Object on the stack 
    Object myObject1; 

    // Create instance of a pointer to Object on the stack 
    Object *myObject2; 

    // Create instance of Object on the Heap and assigned its address to the pointer. 
    myObject2 = new Object; 

    return 0; 
}