MST

星途 面试题库

面试题:C++类内成员函数优化之资源管理与效率

假设你有一个C++类,其中的成员函数涉及大量资源的分配与释放(例如内存、文件句柄等)。请阐述如何通过优化成员函数来避免资源泄露,同时提高整体的运行效率,并且描述相关优化策略在多线程环境下的注意事项。
12.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

避免资源泄露与提高运行效率的优化策略

  1. 资源管理采用RAII(Resource Acquisition Is Initialization)
    • 使用智能指针(std::unique_ptrstd::shared_ptr)来管理动态分配的内存。例如,如果成员函数中分配了一块内存,不要使用原始指针,而是用std::unique_ptr
class MyClass {
private:
    std::unique_ptr<int[]> data;
public:
    MyClass(int size) : data(std::make_unique<int[]>(size)) {}
    // 其他成员函数
};
- 对于文件句柄等非内存资源,可以自定义RAII类。例如:
class FileRAII {
private:
    FILE* file;
public:
    FileRAII(const char* filename, const char* mode) : file(fopen(filename, mode)) {
        if (!file) {
            throw std::runtime_error("Failed to open file");
        }
    }
    ~FileRAII() {
        if (file) {
            fclose(file);
        }
    }
    FILE* getFile() {
        return file;
    }
};
  1. 减少不必要的分配与释放
    • 尽量使用对象池技术。如果频繁创建和销毁相同类型的对象,可以预先创建一定数量的对象放在对象池中,需要时从池中获取,使用完后放回池中,避免反复的内存分配和释放开销。
    • 对于动态数组,可以使用std::vectorreserve方法预先分配足够的空间,减少动态扩展时的重新分配次数。例如:
std::vector<int> vec;
vec.reserve(100); // 预先分配100个元素的空间
for (int i = 0; i < 100; ++i) {
    vec.push_back(i);
}
  1. 异常安全
    • 确保成员函数是异常安全的。如果在资源分配过程中抛出异常,已经分配的资源要正确释放。例如,在构造函数中如果部分资源分配成功,而后续资源分配失败抛出异常,已分配的资源应能正确释放。使用RAII机制可以自动满足这一要求。

多线程环境下的注意事项

  1. 资源竞争
    • 对共享资源(如文件句柄、全局数据等)的访问必须进行同步。可以使用互斥锁(std::mutex)来保护共享资源。例如:
std::mutex fileMutex;
FileRAII file("test.txt", "w");
void writeToFile(const char* data) {
    std::lock_guard<std::mutex> lock(fileMutex);
    fprintf(file.getFile(), "%s", data);
}
  1. 智能指针与线程安全
    • std::shared_ptr是线程安全的,但std::unique_ptr不是。在多线程环境下使用std::shared_ptr时,多个线程可以安全地共享对象的所有权。不过,要注意std::shared_ptr的引用计数操作虽然是原子的,但对象的实际访问仍可能需要同步。
  2. 对象池与线程安全
    • 如果使用对象池,对象池本身需要是线程安全的。获取和归还对象的操作需要进行同步,防止多个线程同时获取或归还同一个对象,导致数据竞争。可以使用条件变量(std::condition_variable)来实现线程间的同步,例如:
std::mutex poolMutex;
std::condition_variable poolCV;
std::vector<MyObject*> objectPool;

MyObject* getObjectFromPool() {
    std::unique_lock<std::mutex> lock(poolMutex);
    while (objectPool.empty()) {
        poolCV.wait(lock);
    }
    MyObject* obj = objectPool.back();
    objectPool.pop_back();
    return obj;
}

void returnObjectToPool(MyObject* obj) {
    std::unique_lock<std::mutex> lock(poolMutex);
    objectPool.push_back(obj);
    poolCV.notify_one();
}