生命期 (lifetime): 带输出的构造、析构如何阅读?#
前置内容
考试中这类题目所关注的是构造函数和析构函数的调用时机, 即对象的生命期什么时候开始、什么时候结束.
对象的生老病死为:
- 对象被创建/构造 (created/constructed)
对象所需的存储空间 (storage) 被分配 (allocated).
2这里的初始化包括默认初始化 (如 对象被初始化 (initialized) 2这里的初始化包括默认初始化 (如
std::string string;
) 中实际不进行初始化的情况 (如int value;
)., 进而开始 (begins) 其生命期 (lifetime). 这个过程中, 自定义类型的构造函数将被调用.
std::string string;
) 中实际不进行初始化的情况 (如int value;
).- 对象被使用
在对象的生命期期间, 它可以根据其类型被合法使用.
- 对象被销毁 (destroyed)
对象被销毁 (destroyed), 进而结束 (ends) 其生命期. 这个过程中, 自定义类型的析构函数将被调用.
对象所用的存储空间被解分配 (deallocated).
由此, 对象具有两个属性: 生命期 (lifetime) 和存储周期 (storage duration).
- 生命期
只有在对象的生命期期间, 对象才被认为是合法的, 可以根据其类型被合法使用.
1int* function() { 2 int value; // value 被创建 (分配存储空间 + 开始生命期) 3 value = 0; // 生命期内, int 类型的 value 可以被赋值 4 return &value; 5} // value 被销毁 (结束生命期 + 解分配存储空间) 6 7int main() { 8 int* pointer = function(); 9 *pointer = 10; // 未定义行为: 对象的生命期已经结束 10}
- 存储周期
存储周期描述什么时候为对象分配存储空间和初始化对象, 以及该存储空间会存在多久. 显然, 在对象的生命期期间其存储空间必须存在, 所以存储周期决定了对象的生命期最长能持续多久.
在课程范围内, 对象的生命期总是与存储空间的持续时间等同.
别看: 对象的生命期可以短于存储空间的持续时间
1// 假设 sizeof(int) == sizeof(float) 2int main() { 3 int i; // i 被创建 (分配存储空间 + 开始生命期) 4 i = 1; 5 6 float* f = new (&i) float; // i 结束生命期, f 开始生命期 7 f = 1.5; 8 9 // i = 1; // 未定义行为: i 的生命期已经结束 10} // f 被销毁 (结束生命期 + 解分配存储空间)
警告
由于不清楚考试如何给的答案, 练习题中没有涉及一些模糊的和强制禁止优化也会被优化掉的地方 (例如用函数返回值构造具名对象).