什么是析构函数析构函数是一种特殊的类成员函数,当该类对象被销毁时自动执行。构造函数负责初始化,而析构函数专门用于清理资源。

当对象正常离开作用域,或通过 delete 显式销毁动态分配的对象时,若存在析构函数,系统会在对象从内存中移除之前自动调用它,完成必要的清理工作。对于仅含普通成员变量的简单类,C++ 会自动回收内存,无需自定义析构函数;但若类持有资源(如动态内存、文件句柄、数据库连接等),或需要在对象销毁前执行维护操作,则应将逻辑放在析构函数中,这是最后且最合适的时机。

命名规则与构造函数类似,析构函数遵循严格的命名约定:

必须与类同名,且前缀为波浪号 ~;不得接受任何参数;无返回类型;每个类只能有一个析构函数。一般而言,不应显式调用析构函数(因其会在对象销毁时自动触发),极少需要多次清理同一对象。然而,析构函数内部可安全调用其他成员函数,因为对象只有在析构函数执行完毕后才真正销毁。

析构函数示例以下示例展示了一个简单类如何使用析构函数:

#include

#include

#include

class IntArray

{

private:

int* m_array{};

int m_length{};

public:

IntArray(int length) // 构造函数

{

assert(length > 0);

m_array = new int[static_cast(length)]{};

m_length = length;

}

~IntArray() // 析构函数

{

// 释放先前分配的数组

delete[] m_array;

}

void setValue(int index, int value) { m_array[index] = value; }

int getValue(int index) { return m_array[index]; }

int getLength() { return m_length; }

};

int main()

{

IntArray ar(10); // 分配 10 个整数

for (int count{ 0 }; count < ar.getLength(); ++count)

ar.setValue(count, count + 1);

std::cout << "第 5 个元素的值为: " << ar.getValue(5) << '\n';

return 0;

} // ar 在此离开作用域,~IntArray() 被自动调用

提示若编译上述示例时出现以下错误:

error: 'class IntArray' has pointer data members [-Werror=effc++]

error: but does not override 'IntArray(const IntArray&)' [-Werror=effc++]

error: or 'operator=(const IntArray&)' [-Werror=effc++]

可在编译设置中移除 -Weffc++ 标志,或在类内添加:

IntArray(const IntArray&) = delete;

IntArray& operator=(const IntArray&) = delete;

(`=delete` 用法参见《拷贝构造函数简介》)

程序运行结果:

第 5 个元素的值为: 6

在 main() 第一行创建 IntArray 对象 ar 并传入长度 10,构造函数动态分配数组内存。main() 结束时 ar 离开作用域,析构函数自动释放数组。

提醒

在 《std::vector 与列表构造函数简介》中提到,当初始化数组/容器/列表类且仅指定长度而非元素列表时,应使用括号初始化。因此示例采用 `IntArray ar(10);`。

## 构造与析构的时机

以下示例在构造与析构函数中加入打印语句,以展示调用顺序:

```cpp

#include

class Simple

{

private:

int m_nID{};

public:

Simple(int nID) : m_nID{ nID }

{

std::cout << "构造 Simple " << nID << '\n';

}

~Simple()

{

std::cout << "析构 Simple" << m_nID << '\n';

}

int getID() { return m_nID; }

};

int main()

{

Simple simple{ 1 }; // 栈上分配

std::cout << simple.getID() << '\n';

Simple* pSimple{ new Simple{ 2 } }; // 动态分配

std::cout << pSimple->getID() << '\n';

delete pSimple; // 手动销毁

return 0;

} // simple 在此离开作用域

输出:

构造 Simple 1

1

构造 Simple 2

2

析构 Simple 2

析构 Simple 1

由于先 delete pSimple,后离开 main(),故 “Simple 1” 在 “Simple 2” 之后析构。

全局变量在 main() 之前构造,在 main() 之后析构。

RAIIRAII(Resource Acquisition Is Initialization,资源获取即初始化)是一种编程技术,将资源使用与具有自动存储期的对象生命周期绑定。在 C++ 中,通过类的构造函数获取资源,在析构函数释放资源:

通常在构造函数中申请资源(如内存、文件句柄等),在析构函数中释放资源。RAII 的最大优势是防止资源泄漏——所有持有资源的对象都会被自动清理。本课顶部的 IntArray 类即 RAII 示例:构造函数分配,析构函数释放。std::string 与 std::vector 也是标准库中遵循 RAII 的类:初始化时获取动态内存,销毁时自动清理。

关于 std::exit() 的警告若使用 std::exit() 终止程序,不会调用任何析构函数。若依赖析构函数完成必要清理(如写日志、关闭数据库连接),请务必小心。

小结当构造函数与析构函数协同工作时,类可在创建时自我初始化,在销毁时自我清理,无需程序员额外介入。这不仅降低出错概率,也使类更易使用。