MST

星途 面试题库

面试题:C++ 重写拷贝构造函数与资源管理及异常安全

设计一个 `DatabaseConnection` 类,它封装了数据库连接资源(例如通过一个句柄表示)。要求重写拷贝构造函数,确保在拷贝对象时,资源得到正确管理,同时保证整个操作的异常安全性,即在任何异常情况下,资源不会泄露且对象处于有效状态。请详细说明你的设计思路并给出代码实现。
45.0万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 资源管理:使用RAII(Resource Acquisition Is Initialization)原则来管理数据库连接资源。在构造函数中获取资源(如打开数据库连接并获取句柄),在析构函数中释放资源(如关闭数据库连接)。
  2. 拷贝构造函数:实现深拷贝,确保每个对象都有自己独立的资源。当拷贝对象时,创建一个新的数据库连接句柄,而不是共享原对象的句柄。
  3. 异常安全性:在构造和拷贝过程中,确保在任何异常情况下资源都能正确释放。使用try - catch块捕获可能抛出的异常,并在异常发生时清理已获取的资源。

代码实现(以C++为例)

#include <iostream>
#include <stdexcept>

class DatabaseConnection {
private:
    // 假设这是数据库连接句柄
    void* connectionHandle;

public:
    // 构造函数
    DatabaseConnection() {
        // 模拟获取数据库连接
        connectionHandle = nullptr;
        try {
            // 这里可能是实际获取连接的操作,例如调用数据库API
            connectionHandle = reinterpret_cast<void*>(new char[1]);
        } catch (const std::bad_alloc& e) {
            std::cerr << "Failed to allocate memory for connection handle: " << e.what() << std::endl;
            // 这里可以进行更具体的资源清理,由于模拟简单,暂不做更多处理
            throw;
        }
    }

    // 拷贝构造函数
    DatabaseConnection(const DatabaseConnection& other) {
        // 模拟深拷贝,创建新的数据库连接
        connectionHandle = nullptr;
        try {
            // 这里可能是实际获取连接的操作,例如调用数据库API
            connectionHandle = reinterpret_cast<void*>(new char[1]);
        } catch (const std::bad_alloc& e) {
            std::cerr << "Failed to allocate memory for connection handle in copy constructor: " << e.what() << std::endl;
            // 这里可以进行更具体的资源清理,由于模拟简单,暂不做更多处理
            throw;
        }
    }

    // 析构函数
    ~DatabaseConnection() {
        // 模拟释放数据库连接
        if (connectionHandle != nullptr) {
            delete[] reinterpret_cast<char*>(connectionHandle);
            connectionHandle = nullptr;
        }
    }

    // 赋值运算符重载(为了代码完整性,这里简单实现,实际应用中可能更复杂)
    DatabaseConnection& operator=(const DatabaseConnection& other) {
        if (this != &other) {
            // 释放当前资源
            if (connectionHandle != nullptr) {
                delete[] reinterpret_cast<char*>(connectionHandle);
            }
            // 深拷贝资源
            try {
                connectionHandle = reinterpret_cast<void*>(new char[1]);
            } catch (const std::bad_alloc& e) {
                std::cerr << "Failed to allocate memory in assignment operator: " << e.what() << std::endl;
                // 这里可以进行更具体的资源清理,由于模拟简单,暂不做更多处理
                throw;
            }
        }
        return *this;
    }
};

以上代码通过RAII管理数据库连接资源,在构造、拷贝构造和赋值运算符重载中都考虑了异常安全性,确保在任何异常情况下资源都不会泄露且对象处于有效状态。实际应用中,connectionHandle 应该是真实的数据库连接句柄,获取和释放连接的操作应替换为实际的数据库API调用。