2015-11-03 93 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分配一个不同的值)。


这将构成存储器泄漏,因为一个动态分配的对象,其地址已经丢失不能由程序被删除。