【c++】【智能指针】什么情况下不适合智能指针
【c++】【智能指针】什么情况下不适合智能指针
1. 性能开销
大多数场景下用到的都是 unique_ptr
- 代表的是专属所有权,即由 unique_ptr 管理的内存,只能被一个对象持有。
- unique_ptr 不支持复制和赋值
- unique_ptr 在默认情况下和裸指针的大小是一样的。所以内存上没有任何的额外消耗,性能是最优的
shared_ptr:共享所有权
- 使用 shared_ptr 之前应该考虑,是否真的需要使用 shared_ptr, 而非 unique_ptr。
- shared_ptr 代表的是共享所有权,即多个 shared_ptr 可以共享同一块内存。
- shared_ptr 是支持复制的。
- shared_ptr性能开销更大,内存占用是裸指针的两倍。因为除了要管理一个裸指针外,还要维护一个引用计数。
因此相比于 unique_ptr, shared_ptr 的内存占用更高
std::shared_ptr
的引用计数机制会引入额外的性能开销,
std::unique_ptr
性能更接近裸指针,但在某些场景下仍存在额外的构造、析构或转移开销。
2. 不适合所有场景
- 智能指针主要管理堆内存,对栈上对象、全局对象或静态对象无效。
- 对于某些短生命周期的局部变量,栈分配更高效,无需使用智能指针。
void func() {
int a = 10; // 栈上对象,生命周期由作用域自动管理,使用智能指针反而增加不必要的开销。
}
3. 循环引用问题
std::shared_ptr
存在循环引用的风险,会导致内存泄露。- 解决循环引用需要使用
std::weak_ptr
,但引入weak_ptr
也会增加代码复杂度。
示例:循环引用导致的内存泄漏
#include <iostream>
#include <memory>
using namespace std;
struct B; // 前向声明
struct A {
shared_ptr<B> ptr; // A指向B
~A() { cout << "A 被销毁" << endl; }
};
struct B {
shared_ptr<A> ptr; // B指向A
~B() { cout << "B 被销毁" << endl; }
};
int main() {
auto a = make_shared<A>();
auto b = make_shared<B>();
a->ptr = b;
b->ptr = a;
// 程序退出时 A 和 B 的析构函数都未调用,发生内存泄漏
return 0;
}
4. 控制权与灵活性
- 在某些情况下,使用裸指针更直观,尤其当对象的生命周期由其他机制管理时。
- 智能指针默认会在生命周期结束时释放资源,若不小心在
非预期时间释放,可能引发程序错误
。
示例:部分
C API
要求使用裸指针,如malloc()
、free()
、pthread
等。
5. 兼容性
- 一些 C++ 库和框架可能不兼容智能指针,需要使用裸指针来适配。
6. 代码的可读性和复杂度
- 滥用智能指针可能会降低代码的可读性,尤其在复杂的层次结构中,理解 shared_ptr、unique_ptr、weak_ptr 之间的关系可能变得困难。