C++ 智能指针
一、智能指针类型概览
C++ 标准库提供以下智能指针(需包含头文件 <memory>
):
- unique_ptr:独占所有权,不可复制, 可移动
- shared_ptr:共享所有权,用于引用计数
- weak_ptr:观察 shared_ptr 对象,不增加计数
二、unique_ptr(独占指针)
核心特性:
- 唯一拥有指向对象的所有权
- 支持移动语义(所有权转移)
- 离开作用域自动释放内存
#include <iostream>
#include <memory>void unique_ptr_demo() {// 创建智能指针 (C++14推荐make_unique)std::unique_ptr<int> p1 = std::make_unique<int>(10);// 访问数据std::cout << *p1 << std::endl; // 输出:10// 所有权转移std::unique_ptr<int> p2 = std::move(p1);std::cout << (p1 ? "非空" : "空") << std::endl; // 输出:空
}int main() {unique_ptr_demo();return 0;
}
三、shared_ptr(共享指针)
核心特性:
- 通过引用计数共享所有权
- 最后一个指针销毁时释放内存
- 支持自定义删除器
#include <iostream>
#include <memory>class Data {
public:Data() { std::cout << "Data构造" << std::endl; }~Data() { std::cout << "Data析构" << std::endl; }
};void shared_ptr_demo() {std::shared_ptr<Data> p1;{ // 内部作用域auto p2 = std::make_shared<Data>();p1 = p2; // 共享所有权std::cout << "引用计数: " << p1.use_count() << std::endl; // 输出:2}std::cout << "引用计数: " << p1.use_count() << std::endl; // 输出:1
}int main() {shared_ptr_demo();return 0;
}
share_ptr引起的循环引用的问题。循环引用就是内存泄漏。 因为对象之间相互引用,使得引用计数永远不会变为 0 ,对象所占用的堆内存一直无法被释放。随着程序运行,不断出现这种循环引用的情况,会导致可用内存越来越少,最终可能使程序崩溃,或者引发系统性能问题。
#include <memory>
#include <iostream>class B;
class A {
public:std::shared_ptr<B> bptr;~A() {std::cout << "~A()" << endl;}
};class B {
public:std::shared_ptr<A> aptr;~B() {std::cout << "~B()" << endl;}
};int main() {std::shared_ptr<A> aa = std::make_shared<A>();std::shared_ptr<B> bb = std::make_shared<B>();aa->bptr = bb;bb->aptr = aa;return 0;
}
四、weak_ptr(弱指针)
weak_ptr 是一种弱引用智能指针,它指向由 shared_ptr 管理的对象,但不增加对象的引用计数
核心特性:
- 不增加引用计数
- 解决 shared_ptr 循环引用问题
- 必须转换为 shared_ptr 才能访问数据
#include <iostream>
#include <memory>class Node {
public:std::weak_ptr<Node> partner; // 使用weak_ptr打破循环~Node() { std::cout << "节点销毁" << std::endl; }
};void weak_ptr_demo() {auto node1 = std::make_shared<Node>();auto node2 = std::make_shared<Node>();node1->partner = node2;node2->partner = node1;if(auto sp = node1->partner.lock()) { std::cout << "有效伙伴节点" << std::endl; }
}int main() {weak_ptr_demo();return 0;
}
五、编译与运行
-
编译命令:
g++ -std=c++14 -o smart_ptr_demo smart_ptr_demo.cpp
-
运行结果:
Data构造 引用计数: 2 引用计数: 1 Data析构 节点销毁 节点销毁
六、选择指南
指针类型 | 使用场景 | 性能开销 |
---|---|---|
unique_ptr | 独占资源的场景(90%日常使用) | 无 |
shared_ptr | 需要共享所有权的复杂场景 | 有 |
weak_ptr | 解决循环引用或观察共享资源 | 低 |
最佳实践:
- 优先使用
make_unique
/make_shared
创建指针 - 避免裸指针与智能指针混用
- 明确所有权关系,能用
unique_ptr
就不用shared_ptr