2015-11-03 59 views
0

考慮下面的代碼段:C++:靜態指針,靜態對象和動態存儲器分配

#include <iostream> 
using namespace std; 

class p 
{ 
    public: 
    int* q; 
    p() 
    { 
     q = new int(100); 
    } 
    ~p(){ 
     delete q; 
    } 
}; 

static p* p1 = new p(); 
static p p2; 

int main() { 
    // your code goes here 
    std::cout << *(p1->q); 
    std::cout << *(p2.q); 

    delete p1; 
} 

p1和p2是靜態的VARS,它們必須存儲在靜態段。

  1. 因爲p1是一個指針,只是指針地址存儲在靜態段或者它指向的對象中?

  2. p2是一個普通的靜態對象,但它包含一個動態分配的成員變量q,所以q也存儲在靜態段中?

+0

不,沒有。更重要的是,你不應該在意。 –

+0

爲什麼不運行代碼並親自查看? – CrakC

+0

@CrakC對於C++來說,這通常不是一個好主意。 – Quentin

回答

3
  1. p1是一個指針,它存儲在靜態段(我不知道這是正確的術語),對象或內存p1點上堆。

  2. p2是一個對象,它存儲在靜態段中。 qp2內的指針,對象或內存q指向堆上。

0

你這是靜態分配,一個名爲p1指針和一個名爲p2p類型的實例兩個對象。

在程序中有兩個地方可以進行動態分配:在類p的構造函數中以及靜態變量p1被初始化時。

只要程序運行,靜態分配的對象p1(指針)和p2(類實例)就存在。區分指針p1只包含該地址的類實例的地址很重要。(該實例將在運行時創建new p())。指針和「指針」可以有獨立的生命週期;兩者彼此獨立存在。指針可能存在並且不指向任何東西,並且由new p()調用創建的對象可能比指向它的任何指針存在更長的時間。

下面是當您的程序啓動時展開的事件序列。 C++ 11標準的第3.6.2節中指定了靜態變量的初始化。

  1. 分配與靜態存儲時間這裏p1p2變量。這種工作模式是內存是程序的一部分。

  2. 這些變量歸零。「在進行任何其他初始化之前,應將靜態存儲持續時間[...]的變量進行零初始化。」指針p1以及p2所在的內存現在由全爲零的字節組成。在其定義的順序這些變量的

  3. 動態(即運行時)初始化:

    p1與主叫new p()開始指針的
    • 初始化。
      • p類型的新對象的內存使用標準分配器動態分配(「在堆上」)。內存的內容未初始化且未知。該對象沒有名稱,所以我們稱它爲x
      • x'構造函數被執行以初始化它。
        • 該構造函數爲迄今爲止未初始化的成員變量x.q分配一個值。 x.qx的一部分,並且因此駐留在之前動態分配的存儲器中。
        • 作業的右側是new的另一個調用,此時爲int。標準分配器動態分配一個int值,初始化爲100.
        • new的返回值是int所在的內存地址,它分配給int指針x.q
      • x'構造函數返回,和返回new p()的存儲器地址,其中x駐留。
      • 此返回值分配給迄今爲零初始化的p1,它現在指向我們稱爲x的未命名的p實例。
    • 初始化p2p2的構造函數與上面的x的構造函數執行的操作相同:它調用new來獲得動態內存分配的int,並將其初始化爲100,並將int的內存位置的地址賦值爲p2.q

結果,據的存儲器位置和對象之間的關係而言,被顯示在下面的圖所示。

Memory schematics of your program

這將有助於回答您的問題:

  1. p1處於「靜態部分」,如果你想要的,但它指向的對象來一直在運行時動態分配致電new
  2. 靜態對象p2不包含包含「一個動態分配的成員變量q」。該句混淆了成員變量 - 一個名爲q的指針 - 與對象q點,這是一個動態分配的int。成員變量q存儲在存儲類p的包含實例的任何位置;實際上,它該實例中唯一的數據。 (嘗試sizeof(p)!)任何實例的成員q指向的對象始終是一個動態分配的int(好吧,直到某個惡意程序員爲你的公共q分配一個不同的值)。


這將構成存儲器泄漏,因爲一個動態分配的對象,其地址已經丟失不能由程序被刪除。