c++编程实践—如何理解生命周期

一、生命周期

生命周期,Lifetime,就是一个事物从出现到结束的全过程的时间范围。生命周期这个概念对于传统的C++程序员来说,其实并不那么清晰。它不如其它语言如java,C#以及新出现的Rust等语言中,都有明确的时间周期的相关分析说明。因为在这些语言中,资源的管理都是隐式的,即由垃圾回收器或运行时进行。这对于开发者来说,可以认为是一种福音。所以它们对于程序员来说,需要明确生命周期的全过程。

但c++这类语言是相信开发者的,生命周期完全交给开发者,由开发者自行进行生命周期的管理。这就带来了致命的问题,并不是所有的开发者,都是一个合格的资源的生命周期管理者。即使是合格的开发者,也可能因为各种意外导致生命周期管理的异常。这就意味着资源的泄露或者说崩溃。

二、c++中的生命周期

c++之所以为开发者诟病,一个重要原因是资源的管理,包括但不限制最重要的内存资源。具像化出来,就是指针的操作。资源的应用,必须在其生命周期的可用用范围内。如果在之外,要么返回一个错误值,但更大的可能直接就崩溃了。

c++开发中,资源的种类有很多,如变量、指针、内存、句柄、io等等。表现形式也五花八六,光内存就可以有缓冲、内存池、对象等等。这也让很多的初学者感到迷惑。其实,对于绝大多数的资源,基本都可以划到内存资源中来。比如对象和句柄,往往其内部就是一块的内存。

c++中内存的分配和回收有很多种机制,可以是栈(自动操作)、堆(手工分配),也可以表现为类的构造和析构函数。不同的表现情况,可能需要不同的处理机制和注意点。这在前面的相关细节的分析中都反复的说明过。

一般来说,c++的生命周期还是可以通过下面的不同情况来进行较为明确的划分:

  1. 自动存储对象生命周期
    它主要是栈对象,主要就是函数内部的临时变量、参数;代码块内的临时变量以及其它一些特定情况下的临时对象(如拷贝或返回值中的临时变量)等。它的生命周期由编译器和运行时自动进行管理,效率非常高。它的生命周期基本是从声明开始到作用域结束也就是结束了
  2. 静态存储对象生命周期
    这种对象包括全局变量、静态变量。它的生命周期一般也是自动由编译器和运行进行管理,其生命周期贯穿整个程序的生命周期,它在main函数前创建在程序结束时结束
  3. 动态存储对象生命周期
    这是c++程序员最复杂的生命周期管理,它包括各种对象、变量以及内存指针等。其生命周期由开发者全权负责。它一般从new/malloc分配开始,到delete/free时结束。这种对象的生命周期复杂多变,而且受到各种意外情况的干涉(比如接口暴露出一个指针,应用方给释放了)。所以在这种情况下,一般建议是使用智能指针来操作,尽可能防止出现意外

三、生命周期的意义

需要跳出来说一下。生命周期是爱其它依赖影响的。比如,一块分配的内存依赖于一个进程管理,而一个进程依赖于操作系统,而操作系统又依赖于硬件。当强制关闭电源时,相关的所有生命周期自然就结束了。所以,这里的讨论和分析其实就是基于正常的标准情况下的分析。

生命周期核心就是资源管理,而资源对于计算机来说,对于需求来说,是永远不会满足的。原来一个游戏有个几百M就很大了,后来到G,而现在动辙就几十G

。c++没有垃圾回收,没有如Rust那样强制的所有权管理进行间接的生命周期管理。所以,其对资源的安全应用以及分配回收就成为了一个头等重要的问题。c++语言先是提供了RAII的资源管理机制,又在新标准中提供了智能指针,但这都无法从整体上控制开发者对资源的安全管理。因此,对于c++开发者来说,资源的生命周期的管理,仍然是一个极其重要的问题。

四、新标准的发展

随着c++11及之后的标准的快速迭代和演进,新的对于生命周期的控制或者说对资源管理的机制不断推出。如移动语义、各种智能指针。特别是在c++17中提供了std::launder,用于在延长同一内存的对象更换(不满足透明可替换),而在c++23中则提供了显式的生命周期管理如std::start_lifetime_as

应用显式的告诉编译器一个对象启动了。这两个函数在前面都有过详细的分析说明,不清楚的可以回头翻一下。

也就是说,c++的新标准的发展,一定是强生命周期、显式生命周期的管控为方向,尽量减少或控制隐式生命周期的处理。不同的场景下,对效率和性能的要求不同,而通过对象生命周期的动态管理,可以有效的提高性能和效率(如移动 语义和刚刚的两人个函数)。

五、总结

从原则上来讲,生命周期越是自动控制或显式可控就越简单方便。但对于c++这种语言来说,不太符合实际情况。所以针对资源,特别是内存,一般是首选RAII,在新标准中强烈推荐使用智能指针来管理堆内存,并严格厘清不同智能指针的应用场景。对于一些可将临时对象的生命周期进行延长的技术手段要谨慎使用(如绑定到右值引用或const左值引用等)。

总体上来说,生命周期对于c++来说是一种极其灵活的存在,开发者要善于通过各种技术手段来限制生命周期的范围,不能任意的延长或缩短资源的生命周期。所谓恰到好处,正是如此!

相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
weilx12342 天前
C++笔记-文件IO-<fcntl.h>
c++
Smileyqp沛沛2 天前
前端?C++ ?较大差异基础罗列
c++·基础·前端转c++
C语言小火车2 天前
C/C++ 为什么需要编译器?
开发语言·c++
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
吞下星星的少年·-·2 天前
C++ 萌新语法入门篇
c++·算法比赛
霍霍的袁2 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
another heaven2 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
程序猿编码2 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
此生决int2 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++