面试题答案
一键面试面临的挑战
- 竞态条件:多个线程可能同时尝试访问对象的析构函数,导致共享资源的释放出现竞争,可能引发未定义行为。
- 资源泄漏:如果析构函数没有正确同步,可能导致共享资源(如数据库连接)没有被正确释放,造成资源泄漏。
可能导致资源释放问题的场景
- 线程 A 正在使用对象资源时,线程 B 触发对象析构:线程 A 可能继续使用已被析构的资源,导致程序崩溃。
- 多个线程同时调用析构函数:由于竞态条件,可能导致共享资源被释放多次,或者部分释放不完全。
解决方案
1. 互斥锁(Mutex)
- 优点:实现简单,是一种常见且成熟的同步机制。可以有效避免多个线程同时进入析构函数,保证资源释放的安全性。
- 缺点:引入额外的同步开销,可能影响程序性能。如果锁的使用不当(如死锁),会导致程序无法正常运行。
2. 智能指针(如 std::shared_ptr 结合自定义删除器)
- 优点:自动管理对象的生命周期,通过引用计数机制,只有当所有指向对象的指针都被销毁时,才会调用析构函数。自定义删除器可以用于释放共享资源,确保资源安全释放。
- 缺点:增加了代码的复杂性,需要理解引用计数的原理和智能指针的使用规则。在循环引用的情况下,可能导致内存泄漏,需要使用 std::weak_ptr 来解决。
3. 线程安全的单例模式(如果对象是单例)
- 优点:确保对象在整个程序中只有一个实例,并且访问和销毁都是线程安全的。对于持有共享资源的对象,这种模式可以有效管理资源的释放。
- 缺点:不适用于非单例对象。单例模式可能导致全局状态,使代码的可测试性和可维护性降低。