C ++:静态指针,静态对象和动态内存分配

时间:2015-11-03 06:15:39

标签: c++ pointers static-members dynamic-memory-allocation

考虑以下代码段:

#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是静态变量,它们必须存储在静态段中。

  1. 因为p1是指针,只是指针地址存储在静态段中,甚至是它指向的对象?

  2. p2是一个普通的静态对象,但它包含一个动态分配的成员变量q,所以q也存储在静态段中吗?

2 个答案:

答案 0 :(得分:4)

  1. p1是一个指针,它存储在静态段中(我不确定它是正确的术语),指向的对象或内存p1在堆上。

  2. p2是一个对象,它存储在静态段中。 qp2内的指针,指向的对象或内存q在堆上。

答案 1 :(得分:1)

您有两个静态分配的对象,一个名为p1的指针和一个名为p的{​​{1}}类型的实例。

程序中有两个位置可以进行动态分配:在类p2的构造函数中以及何时初始化静态变量p

只要程序运行,就会存在静态分配的对象p1(指针)和p1(类实例)。区分仅包含地址的指针p2与该地址的类实例非常重要。(该实例将在运行时由p1创建)。指针和&#34;指针&#34;可以有独立的生命;两者彼此独立存在。指针可能存在而不指向任何内容,new p()调用创建的对象可能比指向它的任何指针都长。 1

以下是程序启动时展开的一系列事件。静态变量的初始化在C ++ 11标准的3.6.2节中规定。

  1. 静态存储时间此处new p()p1的变量分配。一个工作模型是内存是程序的一部分。

  2. 对这些变量进行归零。&#34;具有静态存储持续时间的变量[...]应在进行任何其他初始化之前进行零初始化。&#34;指针p2以及p1所在的内存现在由全部为零的字节组成。

  3. 这些变量的动态(即运行时)初始化按其定义顺序排列:

    • 指针p2的初始化从调用p1开始。
      • 类型new p()的新对象的内存是使用标准分配器动态分配的(&#34;在堆上#34;)。内存的内容未初始化且未知。该对象没有名称,因此我们将其称为p
      • x&#39;执行构造函数以初始化它。
        • 构造函数为迄今未初始化的成员变量x分配值。 x.qx.q的一部分,因此驻留在之前动态分配的内存中。
        • 分配的右侧是对x的另一次调用,这次是对int的调用。标准分配器为int初始化为100。
        • 动态分配内存
        • new的返回值是int所在的内存地址,它被赋值给int指针new
      • x.q&#39;构造函数返回,x返回new p()所在的内存地址。
      • 此返回值指定为迄今为止已初始化为零的x,现在指向我们称为p1的未命名p实例。
    • 执行初始化x p2的构造函数,其执行与上面p2的构造函数相同:它为x调用一个导致动态内存分配的int,用100初始化它并将int的内存位置地址分配给new
  4. 关于内存位置和对象之间的关系,结果如下图所示。

    Memory schematics of your program

    这有助于回答您的问题:

      如果需要,
    1. p2.q位于&#34;静态段&#34;中,但它指向的对象在运行时通过调用p1动态分配。
    2. 静态对象new 包含&#34;动态分配的成员变量q&#34;。该句子将成员变量(名为p2的指针 - 与q指向的对象混淆,是动态分配的int。成员变量q存储在存储类q的包含实例的任何位置;实际上,该实例中唯一的数据。 (尝试p!)任何实例的成员sizeof(p)指向的对象始终是动态分配的int(好吧,直到某个恶意程序员为您的公共{{{ 1}})。
    3. <小时/> 1 这会构成内存泄漏,因为程序永远不会删除地址丢失的动态分配对象。