《C++面向对象高效编程(第2版)》——4.3 C++中的无用单元收集

简介:

本节书摘来自异步社区出版社《C++面向对象高效编程(第2版)》一书中的第4章,第4.3节,作者: 【美】Kayshav Dattatri,更多章节内容可以访问云栖社区“异步社区”公众号查看。

4.3 C++中的无用单元收集

C++面向对象高效编程(第2版)
C++提供类的析构函数专门处理无用单元收集,但是,这并不意味着无用单元收集只发生在析构函数中。实际上,某些其他成员函数也必须考虑无用单元收集。

类的析构函数给予对象最后一次机会释放它所获得的所有资源。在退出某作用域之前,由语言自动为在该作用域中创建的自动(基于栈)对象调用析构函数。此时,对象即将被销毁(也就是说,被对象占用的内存即将被系统回收)。一旦析构函数完成,对象将彻底地消失。

删除(使用delete操作符)指向某对象的指针时,将通过该对象调用对象所属类的析构函数。

TPerson *p;
p = new TPerson(“12-25-95”); // 在堆上创建一个TPerson类对象
// ...
delete p; // 这将通过p所指向的对象,调用TPerson类的析构函数```。
在析构函数执行完毕后,p所指向的内存被释放。TPerson类的构造函数和析构函数的实现,如下所示:

// 第一个构造函数
TPerson::TPerson(const char birthDate[])
    : _ssn(0), _name(0), _birthDate(birthDate), _address(0)
    { / 构造函数体无代码 / }
char Strdup (const char src)  // 辅助函数
{
  char* ptr = new char[strlen(src)+1];
  strcpy(ptr, src);  
  return ptr;
}
// 第二个构造函数
TPerson::TPerson(const char theName[], const char theAddress[],
     unsigned long theSSN, const char theBirthDate[])
   : _ssn(theSSN), _birthDate(theBirthDate)
{ // 初始化_name、_address等
  _name = (theName ? Strdup(theName) : 0);
  _address = (theAddress ? Strdup(theAddress) : 0);
}`
我们已在堆(heap)上为待储存人名中的字符分配内存。析构函数负责释放这些内存。

// 析构函数
TPerson::~TPerson()
{
    delete [] _name;
    delete [] _address;
}```
现在,考虑下面一段代码:

main()
{
    TPerson john(“11-23-45”);
    // ...
    john.SetName(“John Wayne”);
}`
对象john只有出生日期,没有姓名。接下来,我们使用SetName成员函数设置john的姓名。SetName成员函数用来做什么?以下是它的实现代码:

void TPerson::SetName(const char newName[])
{
   unsigned oldLength = _name ? strlen(_name) : 0;
   unsigned newLength = newName ? strlen(newName) : 0;
   if (oldLength < newLength) { // _name中没有足够的空间
     delete [] _name;  // 无用单元收集
     // 使用已定义的Strdup函数
     _name = (newName ? Strdup(newName) : 0);
   }
   else {
     if (newName) strcpy(_name, newName);
     else {delete [] _name; _name = 0;}
   }
}```
我们检查_name中的字符个数是否足够容纳newName,如果不够就删除_name并分配一块新内存。在分配新内存之前,一定要记得释放_name中的存储区,这非常重要。这就是我们所说的生存期内获得资源。对象john的析构函数仍将正常工作,因为_name确保指向有效内存或者为0。

回顾TCar类的例子,当销毁TCar类的对象时,该对象中的对象_owner怎么办?幸运地是,语言提供了帮助。当TCar类对象即将被销毁时,语言将调用包含在TCar类对象中的对象_owner(TPerson类型)的析构函数,确保不会发生资源泄漏。一般而言,在对象即将被销毁时,包含在该对象中的所有对象的析构函数将被递归地调用,直至所有被包含的对象都被销毁。这只适用于按值包含在其他对象中的对象。如果某对象包含指向其他对象的指针,则由析构函数负责显式销毁它们。
相关文章
|
16天前
|
存储 人工智能 BI
【C++面向对象】C++银行卡管理系统(源码+论文)【独一无二】
【C++面向对象】C++银行卡管理系统(源码+论文)【独一无二】
|
24天前
|
算法 IDE Java
【软件设计师备考 专题 】面向对象程序设计语言:C++、Java、Visual Basic和Visual C++
【软件设计师备考 专题 】面向对象程序设计语言:C++、Java、Visual Basic和Visual C++
39 0
|
28天前
|
设计模式 负载均衡 算法
C/C++发布-订阅者模式世界:揭秘高效编程的秘诀
C/C++发布-订阅者模式世界:揭秘高效编程的秘诀
66 1
|
30天前
|
存储 安全 编译器
C++ std::move以及右值引用全面解析:从基础到实战,掌握现代C++高效编程
C++ std::move以及右值引用全面解析:从基础到实战,掌握现代C++高效编程
76 0
|
2月前
|
C语言 C++
【c++】什么是面向对象
【c++】什么是面向对象
【c++】什么是面向对象
|
2月前
|
存储 数据安全/隐私保护 C++
基于C++的面向对象程序设计:类与对象的深入剖析
基于C++的面向对象程序设计:类与对象的深入剖析
38 1
|
3月前
|
存储 Java 编译器
C++——类和对象(了解面向过程和面向对象、初步认识类和对象、类大小的计算、this指针)
C++——类和对象(了解面向过程和面向对象、初步认识类和对象、类大小的计算、this指针)
|
4月前
|
编译器 C++
[C++] 面向对象的三大特性:封装、继承和多态
[C++] 面向对象的三大特性:封装、继承和多态
34 0
|
21天前
|
存储 C++ 容器
C++入门指南:string类文档详细解析(非常经典,建议收藏)
C++入门指南:string类文档详细解析(非常经典,建议收藏)
31 0
|
21天前
|
存储 编译器 C语言
C++入门: 类和对象笔记总结(上)
C++入门: 类和对象笔记总结(上)
30 0