MST

星途 面试题库

面试题:C++ 析构函数在复杂对象关系下资源释放的处理

假设有一个 C++ 程序,存在类 A,类 B 包含类 A 的对象成员,类 C 继承自类 B 并在构造函数中动态分配了额外的资源(如文件句柄)。请阐述在类 C 的对象生命周期结束时,析构函数的调用顺序以及如何确保所有资源(包括类 A 的成员资源和类 C 动态分配的文件句柄)都被正确释放,同时分析可能出现资源泄漏的情况及原因。
20.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 析构函数调用顺序
    • 首先调用类 C 的析构函数。在类 C 的析构函数中,应该释放其在构造函数中动态分配的资源(如文件句柄)。
    • 然后调用类 B 的析构函数。类 B 的析构函数会自动调用类 A 的析构函数来释放类 A 对象成员的资源,因为类 A 是类 B 的对象成员。
  2. 确保资源正确释放的方法
    • 在类 C 的析构函数中,显式释放动态分配的资源(如关闭文件句柄)。例如:
class C : public B {
private:
    FILE* fileHandle;
public:
    C() {
        fileHandle = fopen("example.txt", "r");
        if (fileHandle == nullptr) {
            // 处理打开文件失败的情况
        }
    }
    ~C() {
        if (fileHandle!= nullptr) {
            fclose(fileHandle);
        }
    }
};
  • 确保类 A 和类 B 的析构函数能正确释放各自的资源。如果类 A 有需要手动释放的资源,在类 A 的析构函数中进行释放操作。类 B 的析构函数无需特殊处理类 A 对象成员的释放,因为它会自动调用类 A 的析构函数。
  1. 可能出现资源泄漏的情况及原因
    • 情况一:在类 C 的构造函数中动态分配资源成功,但在后续构造过程中抛出异常。例如:
class C : public B {
private:
    FILE* fileHandle;
public:
    C() {
        fileHandle = fopen("example.txt", "r");
        if (fileHandle == nullptr) {
            // 处理打开文件失败的情况
        }
        // 假设这里有其他可能抛出异常的代码
        throw std::exception("Some error");
    }
    ~C() {
        if (fileHandle!= nullptr) {
            fclose(fileHandle);
        }
    }
};
  • 原因:由于异常抛出,类 C 的析构函数不会被调用,导致文件句柄没有被关闭,从而造成资源泄漏。解决方法是使用智能指针(如 std::unique_ptrstd::shared_ptr)来管理动态分配的资源,这样在异常发生时,智能指针的析构函数会自动释放资源。
  • 情况二:如果类 C 的析构函数没有正确释放动态分配的资源,例如忘记关闭文件句柄:
class C : public B {
private:
    FILE* fileHandle;
public:
    C() {
        fileHandle = fopen("example.txt", "r");
        if (fileHandle == nullptr) {
            // 处理打开文件失败的情况
        }
    }
    ~C() {
        // 忘记关闭文件句柄
    }
};
  • 原因:资源没有在对象生命周期结束时被释放,导致资源泄漏。应在类 C 的析构函数中正确释放资源。