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

相关推荐
码匠许师傅14 小时前
【设计模式精讲】14.外观模式(Facade)
c++·设计模式·uml·外观模式
xxwxx__16 小时前
C++ list 深度解析:从使用原理到模拟实现
开发语言·c++·list
Chester_199916 小时前
CSP202303C.LDAP
开发语言·c++·蓝桥杯·stl
j7~17 小时前
【C++】《unordered系列关联式容器以及哈希底层、哈希冲突、闭散列与开散列完整解析》
c++·哈希算法·开散列·闭散列·unordered_map·unordered_set·哈希底层结构
2402_8828938617 小时前
封装红黑树实现map和set —— 从源码到模拟实现
c++·set·map
神仙别闹19 小时前
基于C++ MFC 实现的智慧公交系统
开发语言·c++·mfc
dear_bi_MyOnly19 小时前
函数模块化:企业级项目高效之道
c++·后端·学习
码匠许师傅19 小时前
【设计模式精讲】13.装饰器模式(Decorator)
c++·设计模式·uml·装饰器模式
OPEN-F20 小时前
C++综合实战:面向对象图书管理系统
开发语言·c++