C++ 智能指针
概述
智能指针是C++11引入的重要特性,用于自动管理动态内存。智能指针通过RAII(Resource Acquisition Is Initialization)原则,在对象生命周期结束时自动释放资源,避免内存泄漏和悬空指针问题。
🔒 unique_ptr - 独占所有权
基础使用
cpp
#include <iostream>
#include <memory>
#include <vector>
class Resource {
private:
std::string name_;
public:
Resource(const std::string& name) : name_(name) {
std::cout << "Resource创建: " << name_ << std::endl;
}
~Resource() {
std::cout << "Resource销毁: " << name_ << std::endl;
}
void doWork() const {
std::cout << name_ << " 正在工作" << std::endl;
}
const std::string& getName() const { return name_; }
};
class UniquePointerDemo {
public:
static void basicUsage() {
std::cout << "=== unique_ptr基础使用 ===" << std::endl;
// 创建unique_ptr
std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>("资源1");
// 访问对象
ptr1->doWork();
std::cout << "资源名称: " << (*ptr1).getName() << std::endl;
// 检查是否为空
if (ptr1) {
std::cout << "ptr1不为空" << std::endl;
}
// 释放所有权
Resource* raw_ptr = ptr1.release();
std::cout << "释放后ptr1是否为空: " << (ptr1 == nullptr) << std::endl;
// 手动删除(通常不推荐)
delete raw_ptr;
// 重新创建
ptr1 = std::make_unique<Resource>("资源2");
// reset - 重置指针
ptr1.reset(new Resource("资源3"));
// 自动销毁在作用域结束时
}
static void moveSemantics() {
std::cout << "\n=== unique_ptr移动语义 ===" << std::endl;
std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>("移动资源");
// 移动构造
std::unique_ptr<Resource> ptr2 = std::move(ptr1);
std::cout << "移动后ptr1是否为空: " << (ptr1 == nullptr) << std::endl;
std::cout << "ptr2是否有效: " << (ptr2 != nullptr) << std::endl;
// 移动赋值
std::unique_ptr<Resource> ptr3;
ptr3 = std::move(ptr2);
if (ptr3) {
ptr3->doWork();
}
}
static void arraySupport() {
std::cout << "\n=== unique_ptr数组支持 ===" << std::endl;
// 数组形式的unique_ptr
std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
// 初始化数组
for (int i = 0; i < 5; ++i) {
arr[i] = i * i;
}
// 访问数组元素
std::cout << "数组内容: ";
for (int i = 0; i < 5; ++i) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
// 自动调用delete[]
}
static void customDeleter() {
std::cout << "\n=== unique_ptr自定义删除器 ===" << std::endl;
// 自定义删除器
auto custom_deleter = [](Resource* r) {
std::cout << "自定义删除器调用" << std::endl;
delete r;
};
std::unique_ptr<Resource, decltype(custom_deleter)>
ptr(new Resource("自定义删除"), custom_deleter);
ptr->doWork();
// 作用域结束时调用自定义删除器
}
};🤝 shared_ptr - 共享所有权
引用计数管理
cpp
#include <iostream>
#include <memory>
#include <vector>
class SharedPointerDemo {
public:
static void basicUsage() {
std::cout << "=== shared_ptr基础使用 ===" << std::endl;
// 创建shared_ptr
std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>("共享资源");
std::cout << "引用计数: " << ptr1.use_count() << std::endl;
{
// 复制构造
std::shared_ptr<Resource> ptr2 = ptr1;
std::cout << "添加ptr2后引用计数: " << ptr1.use_count() << std::endl;
// 赋值操作
std::shared_ptr<Resource> ptr3;
ptr3 = ptr1;
std::cout << "添加ptr3后引用计数: " << ptr1.use_count() << std::endl;
ptr2->doWork();
// ptr2和ptr3在此处销毁
}
std::cout << "内部作用域结束后引用计数: " << ptr1.use_count() << std::endl;
// ptr1在函数结束时销毁,引用计数变为0,对象被删除
}
static void containerUsage() {
std::cout << "\n=== shared_ptr容器使用 ===" << std::endl;
std::vector<std::shared_ptr<Resource>> resources;
// 添加资源
resources.push_back(std::make_shared<Resource>("容器资源1"));
resources.push_back(std::make_shared<Resource>("容器资源2"));
resources.push_back(std::make_shared<Resource>("容器资源3"));
// 获取第一个资源的另一个引用
std::shared_ptr<Resource> extra_ref = resources[0];
std::cout << "第一个资源引用计数: " << extra_ref.use_count() << std::endl;
// 使用资源
for (const auto& res : resources) {
res->doWork();
}
// 清空容器
resources.clear();
std::cout << "容器清空后extra_ref引用计数: " << extra_ref.use_count() << std::endl;
// extra_ref在此处销毁
}
static void cyclicReference() {
std::cout << "\n=== shared_ptr循环引用问题 ===" << std::endl;
struct Node {
int data;
std::shared_ptr<Node> next;
std::shared_ptr<Node> prev; // 这会造成循环引用
Node(int value) : data(value) {
std::cout << "Node创建: " << data << std::endl;
}
~Node() {
std::cout << "Node销毁: " << data << std::endl;
}
};
{
auto node1 = std::make_shared<Node>(1);
auto node2 = std::make_shared<Node>(2);
// 创建循环引用
node1->next = node2;
node2->prev = node1; // 循环引用!
std::cout << "node1引用计数: " << node1.use_count() << std::endl;
std::cout << "node2引用计数: " << node2.use_count() << std::endl;
// 即使离开作用域,由于循环引用,对象也不会被销毁
}
std::cout << "作用域结束,但对象可能未销毁(内存泄漏)" << std::endl;
}
};🔗 weak_ptr - 弱引用
解决循环引用
cpp
#include <iostream>
#include <memory>
class WeakPointerDemo {
public:
static void breakCyclicReference() {
std::cout << "=== weak_ptr解决循环引用 ===" << std::endl;
struct Node {
int data;
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用weak_ptr避免循环引用
Node(int value) : data(value) {
std::cout << "Node创建: " << data << std::endl;
}
~Node() {
std::cout << "Node销毁: " << data << std::endl;
}
void printPrev() {
if (auto prev_shared = prev.lock()) { // 尝试获取shared_ptr
std::cout << "前一个节点: " << prev_shared->data << std::endl;
} else {
std::cout << "前一个节点已被销毁或不存在" << std::endl;
}
}
};
{
auto node1 = std::make_shared<Node>(1);
auto node2 = std::make_shared<Node>(2);
// 设置关系
node1->next = node2;
node2->prev = node1; // weak_ptr,不影响引用计数
std::cout << "node1引用计数: " << node1.use_count() << std::endl;
std::cout << "node2引用计数: " << node2.use_count() << std::endl;
node2->printPrev();
// 正常销毁
}
std::cout << "作用域结束,对象正常销毁" << std::endl;
}
static void observerPattern() {
std::cout << "\n=== weak_ptr观察者模式 ===" << std::endl;
class Subject;
class Observer {
private:
std::weak_ptr<Subject> subject_;
std::string name_;
public:
Observer(const std::string& name) : name_(name) {}
void setSubject(std::weak_ptr<Subject> subject) {
subject_ = subject;
}
void notify() {
if (auto subject = subject_.lock()) {
std::cout << name_ << " 收到通知,主题仍然存在" << std::endl;
} else {
std::cout << name_ << " 收到通知,但主题已被销毁" << std::endl;
}
}
};
class Subject {
private:
std::vector<std::weak_ptr<Observer>> observers_;
public:
Subject() {
std::cout << "Subject创建" << std::endl;
}
~Subject() {
std::cout << "Subject销毁" << std::endl;
}
void addObserver(std::weak_ptr<Observer> observer) {
observers_.push_back(observer);
}
void notifyAll() {
for (auto& weak_obs : observers_) {
if (auto obs = weak_obs.lock()) {
obs->notify();
}
}
}
};
auto subject = std::make_shared<Subject>();
auto observer1 = std::make_shared<Observer>("观察者1");
auto observer2 = std::make_shared<Observer>("观察者2");
// 设置观察关系
observer1->setSubject(subject);
observer2->setSubject(subject);
subject->addObserver(observer1);
subject->addObserver(observer2);
// 通知
subject->notifyAll();
// 销毁一个观察者
observer2.reset();
// 再次通知
subject->notifyAll();
}
static void weakPtrOperations() {
std::cout << "\n=== weak_ptr操作 ===" << std::endl;
std::shared_ptr<Resource> shared = std::make_shared<Resource>("weak测试");
std::weak_ptr<Resource> weak = shared;
std::cout << "shared引用计数: " << shared.use_count() << std::endl;
std::cout << "weak是否过期: " << weak.expired() << std::endl;
// 通过weak_ptr访问对象
if (auto locked = weak.lock()) {
locked->doWork();
std::cout << "通过weak_ptr成功访问" << std::endl;
}
// 销毁shared_ptr
shared.reset();
std::cout << "shared销毁后,weak是否过期: " << weak.expired() << std::endl;
// 尝试访问已销毁的对象
if (auto locked = weak.lock()) {
locked->doWork();
} else {
std::cout << "对象已销毁,无法通过weak_ptr访问" << std::endl;
}
}
};🛠️ 智能指针实践
工厂模式和RAII
cpp
#include <iostream>
#include <memory>
#include <map>
#include <functional>
class SmartPointerPatterns {
public:
// 工厂模式
class ShapeFactory {
public:
enum class ShapeType { CIRCLE, RECTANGLE, TRIANGLE };
static std::unique_ptr<Shape> createShape(ShapeType type) {
switch (type) {
case ShapeType::CIRCLE:
return std::make_unique<Circle>();
case ShapeType::RECTANGLE:
return std::make_unique<Rectangle>();
case ShapeType::TRIANGLE:
return std::make_unique<Triangle>();
default:
return nullptr;
}
}
};
// RAII资源管理
class FileManager {
private:
std::unique_ptr<FILE, std::function<void(FILE*)>> file_;
public:
FileManager(const std::string& filename, const std::string& mode) {
FILE* f = fopen(filename.c_str(), mode.c_str());
if (!f) {
throw std::runtime_error("无法打开文件: " + filename);
}
file_ = std::unique_ptr<FILE, std::function<void(FILE*)>>(
f, [](FILE* fp) {
if (fp) {
std::cout << "关闭文件" << std::endl;
fclose(fp);
}
}
);
}
void write(const std::string& data) {
if (file_) {
fprintf(file_.get(), "%s", data.c_str());
fflush(file_.get());
}
}
bool isOpen() const {
return file_ != nullptr;
}
};
// 缓存系统
class Cache {
private:
std::map<std::string, std::weak_ptr<Resource>> cache_;
public:
std::shared_ptr<Resource> getResource(const std::string& name) {
auto it = cache_.find(name);
if (it != cache_.end()) {
if (auto resource = it->second.lock()) {
std::cout << "从缓存获取: " << name << std::endl;
return resource;
} else {
// 资源已被销毁,从缓存中移除
cache_.erase(it);
}
}
// 创建新资源
std::cout << "创建新资源: " << name << std::endl;
auto resource = std::make_shared<Resource>(name);
cache_[name] = resource;
return resource;
}
void cleanup() {
for (auto it = cache_.begin(); it != cache_.end();) {
if (it->second.expired()) {
it = cache_.erase(it);
} else {
++it;
}
}
}
size_t size() const {
return cache_.size();
}
};
static void demonstratePatterns() {
std::cout << "=== 智能指针设计模式 ===" << std::endl;
// 工厂模式
auto circle = ShapeFactory::createShape(ShapeFactory::ShapeType::CIRCLE);
if (circle) {
circle->draw();
}
// RAII文件管理
try {
FileManager fm("test.txt", "w");
fm.write("Hello, RAII!\n");
std::cout << "文件写入成功" << std::endl;
// 文件在FileManager销毁时自动关闭
} catch (const std::exception& e) {
std::cout << "文件操作错误: " << e.what() << std::endl;
}
// 缓存系统
Cache cache;
{
auto res1 = cache.getResource("资源A");
auto res2 = cache.getResource("资源B");
auto res3 = cache.getResource("资源A"); // 从缓存获取
std::cout << "缓存大小: " << cache.size() << std::endl;
res1->doWork();
res2->doWork();
}
// 清理过期的弱引用
cache.cleanup();
std::cout << "清理后缓存大小: " << cache.size() << std::endl;
}
};
// 辅助类定义
class Shape {
public:
virtual ~Shape() = default;
virtual void draw() const = 0;
};
class Circle : public Shape {
public:
void draw() const override {
std::cout << "绘制圆形" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() const override {
std::cout << "绘制矩形" << std::endl;
}
};
class Triangle : public Shape {
public:
void draw() const override {
std::cout << "绘制三角形" << std::endl;
}
};
int main() {
UniquePointerDemo::basicUsage();
UniquePointerDemo::moveSemantics();
UniquePointerDemo::arraySupport();
UniquePointerDemo::customDeleter();
SharedPointerDemo::basicUsage();
SharedPointerDemo::containerUsage();
SharedPointerDemo::cyclicReference();
WeakPointerDemo::breakCyclicReference();
WeakPointerDemo::observerPattern();
WeakPointerDemo::weakPtrOperations();
SmartPointerPatterns::demonstratePatterns();
return 0;
}总结
智能指针是现代C++内存管理的核心工具,提供了安全高效的资源管理:
智能指针类型
- unique_ptr: 独占所有权,不可复制,可移动
- shared_ptr: 共享所有权,引用计数管理
- weak_ptr: 弱引用,解决循环引用问题
使用场景
| 指针类型 | 适用场景 | 性能特点 |
|---|---|---|
| unique_ptr | 独占资源 | 零开销 |
| shared_ptr | 共享资源 | 原子操作开销 |
| weak_ptr | 观察者模式 | 最小开销 |
最佳实践
- 优先使用
make_unique和make_shared - 避免使用原始指针管理资源
- 使用
weak_ptr打破循环引用 - 利用RAII原则自动管理资源
- 选择合适的智能指针类型
设计原则
- RAII: 资源获取即初始化
- 异常安全: 智能指针提供强异常安全保证
- 清晰所有权: 明确资源所有权语义
- 自动管理: 避免手动内存管理错误
智能指针消除了大部分内存管理错误,是现代C++不可或缺的特性。