1. 智能指针的设计哲学
RAII(资源获取即初始化)原则
cpp
// 传统资源管理的痛点
void risky_function() {
int* raw_ptr = new int(100);
if (some_condition()) {
delete raw_ptr; // 容易忘记释放
return;
}
throw std::runtime_error("错误"); // 异常导致内存泄漏
delete raw_ptr; // 永远不会执行
}
// RAII解决方案
void safe_function() {
std::unique_ptr<int> smart_ptr = std::make_unique<int>(100);
// 无论函数如何退出,资源都会自动释放
}
2. unique_ptr 深度解析
独占所有权的实现原理
cpp
template<typename T>
class SimplifiedUniquePtr {
private:
T* ptr_;
public:
// 构造函数
explicit SimplifiedUniquePtr(T* ptr = nullptr) : ptr_(ptr) {}
// 禁止拷贝
SimplifiedUniquePtr(const SimplifiedUniquePtr&) = delete;
SimplifiedUniquePtr& operator=(const SimplifiedUniquePtr&) = delete;
// 允许移动
SimplifiedUniquePtr(SimplifiedUniquePtr&& other) noexcept
: ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
SimplifiedUniquePtr& operator=(SimplifiedUniquePtr&& other) noexcept {
if (this != &other) {
delete ptr_;
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
return *this;
}
// 析构函数
~SimplifiedUniquePtr() {
delete ptr_;
}
// 操作符重载
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
};
高级用法
cpp
#include <memory>
// 1. 自定义删除器
struct FileDeleter {
void operator()(FILE* file) const {
if (file) {
fclose(file);
std::cout << "文件资源已释放\n";
}
}
};
std::unique_ptr<FILE, FileDeleter> file_ptr(fopen("data.txt", "r"));
// 2. 工厂模式返回unique_ptr
class Widget {
private:
Widget() = default; // 私有构造函数
friend class WidgetFactory;
};
class WidgetFactory {
public:
static std::unique_ptr<Widget> create() {
return std::unique_ptr<Widget>(new Widget());
}
};
// 3. 数组特化
std::unique_ptr<int[]> array_ptr = std::make_unique<int[]>(100);
array_ptr[0] = 42; // 直接使用数组语法
// 4. 释放所有权
auto ptr = std::make_unique<int>(100);
int* raw_ptr = ptr.release(); // unique_ptr不再管理该内存
// 必须手动管理 raw_ptr
delete raw_ptr;
3. shared_ptr 深度解析
引用计数实现原理
cpp
template<typename T>
class SimplifiedSharedPtr {
private:
T* ptr_;
size_t* ref_count_;
void cleanup() {
if (ref_count_ && --(*ref_count_) == 0) {
delete ptr_;
delete ref_count_;
}
}
public:
// 构造函数
explicit SimplifiedSharedPtr(T* ptr = nullptr)
: ptr_(ptr), ref_count_(ptr ? new size_t(1) : nullptr) {}
// 拷贝构造函数
SimplifiedSharedPtr(const SimplifiedSharedPtr& other)
: ptr_(other.ptr_), ref_count_(other.ref_count_) {
if (ref_count_) ++(*ref_count_);
}
// 拷贝赋值
SimplifiedSharedPtr& operator=(const SimplifiedSharedPtr& other) {
if (this != &other) {
cleanup();
ptr_ = other.ptr_;
ref_count_ = other.ref_count_;
if (ref_count_) ++(*ref_count_);
}
return *this;
}
// 移动语义
SimplifiedSharedPtr(SimplifiedSharedPtr&& other) noexcept
: ptr_(other.ptr_), ref_count_(other.ref_count_) {
other.ptr_ = nullptr;
other.ref_count_ = nullptr;
}
~SimplifiedSharedPtr() {
cleanup();
}
size_t use_count() const {
return ref_count_ ? *ref_count_ : 0;
}
};
控制块与内存布局
cpp
// make_shared 的内存优化
auto ptr1 = std::shared_ptr<int>(new int(42)); // 两次分配:对象+控制块
auto ptr2 = std::make_shared<int>(42); // 一次分配:对象和控制块连续
// 控制块包含的信息:
// - 引用计数
// - 弱引用计数
// - 自定义删除器
// - 分配器
循环引用问题详解
cpp
struct BadNode {
std::shared_ptr<BadNode> next;
std::shared_ptr<BadNode> prev;
~BadNode() { std::cout << "Node销毁\n"; } // 永远不会执行
};
void memory_leak_demo() {
auto node1 = std::make_shared<BadNode>();
auto node2 = std::make_shared<BadNode>();
node1->next = node2; // 引用计数: node1=2, node2=1
node2->prev = node1; // 引用计数: node1=2, node2=2
// 离开作用域:引用计数变为1,内存泄漏!
}
// 解决方案:使用weak_ptr
struct GoodNode {
std::shared_ptr<GoodNode> next;
std::weak_ptr<GoodNode> prev; // 弱引用,不增加计数
~GoodNode() { std::cout << "Node销毁\n"; } // 正常执行
};
4. weak_ptr 深度解析
弱引用的实现机制
cpp
// weak_ptr 不参与引用计数,但能感知对象是否存活
std::shared_ptr<int> shared = std::make_shared<int>(100);
std::weak_ptr<int> weak = shared;
// 使用前必须"锁定"
if (auto locked = weak.lock()) {
std::cout << "对象存活,值: " << *locked << std::endl;
} else {
std::cout << "对象已被销毁\n";
}
// expired() 快速检查
if (!weak.expired()) {
auto locked = weak.lock(); // 安全使用
}
典型应用场景
cpp
// 1. 观察者模式
class Subject {
private:
std::vector<std::weak_ptr<Observer>> observers_;
public:
void add_observer(std::weak_ptr<Observer> obs) {
observers_.push_back(obs);
}
void notify() {
for (auto it = observers_.begin(); it != observers_.end(); ) {
if (auto obs = it->lock()) {
obs->update();
++it;
} else {
it = observers_.erase(it); // 清理失效的观察者
}
}
}
};
// 2. 缓存系统
class Cache {
private:
std::unordered_map<std::string, std::weak_ptr<LargeObject>> cache_;
public:
std::shared_ptr<LargeObject> get(const std::string& key) {
auto it = cache_.find(key);
if (it != cache_.end()) {
if (auto cached = it->second.lock()) {
return cached; // 对象仍在内存中
} else {
cache_.erase(it); // 对象已被销毁
}
}
return load_and_cache(key);
}
};
5. 性能分析与优化
性能对比
cpp
#include <chrono>
void benchmark() {
const int iterations = 1000000;
// 原始指针
auto start1 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
int* ptr = new int(i);
delete ptr;
}
auto end1 = std::chrono::high_resolution_clock::now();
// unique_ptr
auto start2 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
auto ptr = std::make_unique<int>(i);
}
auto end2 = std::chrono::high_resolution_clock::now();
// shared_ptr
auto start3 = std::chrono::high_resolution_clock::now();
for (int i = 0; i < iterations; ++i) {
auto ptr = std::make_shared<int>(i);
}
auto end3 = std::chrono::high_resolution_clock::now();
// 输出结果...
}
内存优化技巧
cpp
// 1. 使用make_shared减少内存分配次数
auto bad_ptr = std::shared_ptr<Widget>(new Widget()); // 2次分配
auto good_ptr = std::make_shared<Widget>(); // 1次分配
// 2. 避免不必要的shared_ptr拷贝
void process_widget(std::shared_ptr<Widget> widget); // 按值传递,增加计数
// 优化方案:
void process_widget(const std::shared_ptr<Widget>& widget); // 按引用传递
void process_widget(Widget* widget); // 使用原始指针
// 3. 使用std::move转移所有权
std::vector<std::unique_ptr<Widget>> widgets;
auto widget = std::make_unique<Widget>();
widgets.push_back(std::move(widget)); // 高效的所有权转移
6. 高级特性与自定义
自定义分配器
cpp
template<typename T>
class PoolAllocator {
// 实现内存池分配器
};
class Widget {
public:
static void* operator new(size_t size) {
return pool_allocator.allocate(size);
}
static void operator delete(void* ptr) {
pool_allocator.deallocate(static_cast<Widget*>(ptr));
}
private:
static PoolAllocator<Widget> pool_allocator;
};
// 使用自定义分配器的智能指针
auto widget_ptr = std::allocate_shared<Widget>(PoolAllocator<Widget>());
类型擦除删除器
cpp
class AnyDeleter {
private:
struct Concept {
virtual ~Concept() = default;
virtual void destroy(void*) = 0;
};
template<typename T, typename Deleter>
struct Model : Concept {
Deleter deleter;
Model(Deleter d) : deleter(std::move(d)) {}
void destroy(void* ptr) override {
deleter(static_cast<T*>(ptr));
}
};
std::unique_ptr<Concept> concept_;
public:
template<typename T, typename Deleter>
AnyDeleter(Deleter deleter)
: concept_(std::make_unique<Model<T, Deleter>>(std::move(deleter))) {}
void operator()(void* ptr) {
concept_->destroy(ptr);
}
};
// 使用示例
auto file_deleter = FILE* f { fclose(f); };
std::unique_ptr<FILE, AnyDeleter> file_ptr(fopen("test.txt", "r"),
AnyDeleter<FILE>(file_deleter));
7. 最佳实践总结
选择指南
cpp
// 1. 独占所有权 -> unique_ptr
std::unique_ptr<Resource> resource = acquire_resource();
// 2. 共享所有权 -> shared_ptr
auto shared_resource = std::make_shared<SharedResource>();
// 3. 观察资源 -> weak_ptr
std::weak_ptr<SharedResource> observer = shared_resource;
// 4. 需要数组 -> unique_ptr<T[]> 或 shared_ptr<T> + 自定义删除器
std::unique_ptr<int[]> array = std::make_unique<int[]>(100);
错误用法警示
cpp
// ❌ 错误:从原始指针创建多个shared_ptr
int* raw = new int(42);
std::shared_ptr<int> p1(raw);
std::shared_ptr<int> p2(raw); // 未定义行为,双重释放
// ❌ 错误:循环引用
struct A { std::shared_ptr<B> b; };
struct B { std::shared_ptr<A> a; };
// ❌ 错误:返回unique_ptr的引用
std::unique_ptr<int>& get_ptr(); // 可能意外释放资源
// ✅ 正确做法
// 使用make_shared/make_unique
// 使用weak_ptr打破循环引用
// 按值返回unique_ptr(支持移动语义)
智能指针是现代C++内存管理的核心工具,深入理解其原理和最佳实践对于编写安全高效的C++代码至关重要。