C++:静态指针、静态对象和动态内存分配
C++: Static pointers, static objects and 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 是静态变量,它们必须存储在静态段中。
既然p1是一个指针,那么静态段甚至是它所指向的对象中存储的只是指针地址吗?
p2是一个普通的静态对象,但是它包含了一个动态分配的成员变量q,那么q是不是也存储在静态段中呢?
p1
是一个指针,它存储在静态段中(我不确定这是正确的术语),p1
指向的对象或内存在堆上。
p2
是一个对象,它存储在静态段中。 q
是p2
内部的指针,q
指向的对象或内存在堆上。
您有两个 静态分配的对象 ,一个名为 p1
的指针和一个名为 p2
的类型 p
的实例。
程序中有两个地方可以进行动态分配:在 class p
的构造函数中和初始化静态变量 p1
时。
只要程序 运行s,静态分配的对象 p1
(指针)和 p2
(class 实例)就存在。区分仅包含地址的指针 p1
与位于该地址的 class 实例 很重要。(该实例将在 运行 处创建时间 new p()
)。指针和 "pointee" 可以有独立的生命周期;两者相互独立存在。该指针可能存在但不指向任何东西,并且 new p()
调用创建的对象可能存在的时间比指向它的任何指针都长。1
这是程序启动时展开的事件序列。静态变量的初始化在 C++11 标准的第 3.6.2 节中指定。
变量分配静态存储持续时间,此处p1
和p2
.一个工作模型是内存是程序的一部分。
这些变量的归零。 "Variables with static storage duration [...] shall be zero-initialized before any other initialization takes place." 指针 p1
以及 p2
现在所在的内存由全为零的字节组成。
这些变量的动态(即运行时间)初始化按照它们定义的顺序:
- 指针
p1
的初始化从调用 new p()
开始。
p
类型的新对象的内存是使用标准分配器动态分配的 ("on the heap")。内存的内容未初始化且未知。该对象没有名称,所以我们称它为 x
.
x
' 执行构造函数以对其进行初始化。
- 构造函数为迄今未初始化的成员变量赋值
x.q
。 x.q
是 x
的一部分,因此驻留在之前动态分配的内存中。
- 赋值的右侧是对
new
的另一个调用,这次是一个 int。标准分配器为初始化为 100 的 int 动态分配内存。
new
的return值为int所在的内存地址,赋值给int指针x.q
。
x
'构造函数returns,new p()
returns是x
所在的内存地址。
- 此 return 值被分配给迄今为止零初始化的
p1
,它现在指向我们称为 x
. 的未命名 p
实例
-
p2
. 的初始化 p2
的构造函数被执行,它与上面的 x
的构造函数执行相同的操作:它为导致动态内存分配的 int 调用 new
,用 100 初始化它并将 int 的内存位置的地址分配给 p2.q
.
就内存位置和对象之间的关系而言,结果如下图所示。
这应该有助于回答您的问题:
如果您愿意,p1
在 "static segment" 中,但它指向的对象已在 运行 时间通过调用 new
动态分配。
- 静态对象
p2
不包含"a dynamically allocated member variable q"。这句话混淆了成员变量——一个名为 q
的指针——与 q
指向的对象 , 是一个动态分配的 int。成员变量 q
存储在 class p
的包含实例所在的位置;事实上,它 是 该实例中的唯一数据。 (尝试 sizeof(p)
!)任何实例的成员 q
指向的对象始终是动态分配的 int(好吧,直到某些恶意程序员为您的 public q
).
1这会构成内存泄漏,因为一个地址已经丢失的动态分配的对象永远不会被程序删除。
考虑以下代码段:
#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是不是也存储在静态段中呢?
p1
是一个指针,它存储在静态段中(我不确定这是正确的术语),p1
指向的对象或内存在堆上。p2
是一个对象,它存储在静态段中。q
是p2
内部的指针,q
指向的对象或内存在堆上。
您有两个 静态分配的对象 ,一个名为 p1
的指针和一个名为 p2
的类型 p
的实例。
程序中有两个地方可以进行动态分配:在 class p
的构造函数中和初始化静态变量 p1
时。
只要程序 运行s,静态分配的对象 p1
(指针)和 p2
(class 实例)就存在。区分仅包含地址的指针 p1
与位于该地址的 class 实例 很重要。(该实例将在 运行 处创建时间 new p()
)。指针和 "pointee" 可以有独立的生命周期;两者相互独立存在。该指针可能存在但不指向任何东西,并且 new p()
调用创建的对象可能存在的时间比指向它的任何指针都长。1
这是程序启动时展开的事件序列。静态变量的初始化在 C++11 标准的第 3.6.2 节中指定。
变量分配静态存储持续时间,此处
p1
和p2
.一个工作模型是内存是程序的一部分。这些变量的归零。 "Variables with static storage duration [...] shall be zero-initialized before any other initialization takes place." 指针
p1
以及p2
现在所在的内存由全为零的字节组成。这些变量的动态(即运行时间)初始化按照它们定义的顺序:
- 指针
p1
的初始化从调用new p()
开始。p
类型的新对象的内存是使用标准分配器动态分配的 ("on the heap")。内存的内容未初始化且未知。该对象没有名称,所以我们称它为x
.x
' 执行构造函数以对其进行初始化。- 构造函数为迄今未初始化的成员变量赋值
x.q
。x.q
是x
的一部分,因此驻留在之前动态分配的内存中。 - 赋值的右侧是对
new
的另一个调用,这次是一个 int。标准分配器为初始化为 100 的 int 动态分配内存。 new
的return值为int所在的内存地址,赋值给int指针x.q
。
- 构造函数为迄今未初始化的成员变量赋值
x
'构造函数returns,new p()
returns是x
所在的内存地址。- 此 return 值被分配给迄今为止零初始化的
p1
,它现在指向我们称为x
. 的未命名
p
实例 -
p2
. 的初始化p2
的构造函数被执行,它与上面的x
的构造函数执行相同的操作:它为导致动态内存分配的 int 调用new
,用 100 初始化它并将 int 的内存位置的地址分配给p2.q
.
- 指针
就内存位置和对象之间的关系而言,结果如下图所示。
这应该有助于回答您的问题:
-
如果您愿意,
p1
在 "static segment" 中,但它指向的对象已在 运行 时间通过调用new
动态分配。- 静态对象
p2
不包含"a dynamically allocated member variable q"。这句话混淆了成员变量——一个名为q
的指针——与q
指向的对象 , 是一个动态分配的 int。成员变量q
存储在 classp
的包含实例所在的位置;事实上,它 是 该实例中的唯一数据。 (尝试sizeof(p)
!)任何实例的成员q
指向的对象始终是动态分配的 int(好吧,直到某些恶意程序员为您的 publicq
).
1这会构成内存泄漏,因为一个地址已经丢失的动态分配的对象永远不会被程序删除。