考虑以下代码段:
#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是静态变量,它们必须存储在静态段中。
因为p1是指针,只是指针地址存储在静态段中,甚至是它指向的对象?
p2是一个普通的静态对象,但它包含一个动态分配的成员变量q,所以q也存储在静态段中吗?
答案 0 :(得分:4)
p1
是一个指针,它存储在静态段中(我不确定它是正确的术语),指向的对象或内存p1
在堆上。
p2
是一个对象,它存储在静态段中。 q
是p2
内的指针,指向的对象或内存q
在堆上。
答案 1 :(得分:1)
您有两个静态分配的对象,一个名为p1
的指针和一个名为p
的{{1}}类型的实例。
程序中有两个位置可以进行动态分配:在类p2
的构造函数中以及何时初始化静态变量p
。
只要程序运行,就会存在静态分配的对象p1
(指针)和p1
(类实例)。区分仅包含地址的指针p2
与该地址的类实例非常重要。(该实例将在运行时由p1
创建)。指针和&#34;指针&#34;可以有独立的生命;两者彼此独立存在。指针可能存在而不指向任何内容,new p()
调用创建的对象可能比指向它的任何指针都长。 1
以下是程序启动时展开的一系列事件。静态变量的初始化在C ++ 11标准的3.6.2节中规定。
静态存储时间,此处new p()
和p1
的变量分配。一个工作模型是内存是程序的一部分。
对这些变量进行归零。&#34;具有静态存储持续时间的变量[...]应在进行任何其他初始化之前进行零初始化。&#34;指针p2
以及p1
所在的内存现在由全部为零的字节组成。
这些变量的动态(即运行时)初始化按其定义顺序排列:
p2
的初始化从调用p1
开始。
new p()
的新对象的内存是使用标准分配器动态分配的(&#34;在堆上#34;)。内存的内容未初始化且未知。该对象没有名称,因此我们将其称为p
。x
&#39;执行构造函数以初始化它。
x
分配值。 x.q
是x.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
。关于内存位置和对象之间的关系,结果如下图所示。
这有助于回答您的问题:
p2.q
位于&#34;静态段&#34;中,但它指向的对象在运行时通过调用p1
动态分配。new
不包含&#34;动态分配的成员变量q&#34;。该句子将成员变量(名为p2
的指针 - 与q
指向的对象混淆,是动态分配的int。成员变量q
存储在存储类q
的包含实例的任何位置;实际上,是该实例中唯一的数据。 (尝试p
!)任何实例的成员sizeof(p)
指向的对象始终是动态分配的int(好吧,直到某个恶意程序员为您的公共{{{ 1}})。<小时/> 1 这会构成内存泄漏,因为程序永远不会删除地址丢失的动态分配对象。