手撕STL系列之智能指针
C++11智能指针:
- shared_ptr: 基于引用计数实现
- unique_ptr: 不可以移动的智能指针
- weak_ptr: 解决shared_ptr循环引用问题,更加类似于shared_ptr的管理指针工具。
shared_ptr
shared_ptr是基于引用计数实现,可在生命周期内自动管理内存
我们先实现一个应用计数的类,用atomic实现,保证线程安全:
class SharedCount { public: SharedCount() : count(1) {}
void add() { count++; }
void minus() { count--; }
int get() const { return count; }
private: std::atomic<int> count;
};
|
实现shared_ptr注意点:
- 实现赋值构造函数和移动构造函数,
- 重写拷贝赋值和移动赋值符号
- 再就是shared_ptr的一些其他函数,比如use_count(),get()等方法
- 管理引用计数,在计数==1的时候删除内存。
#include <iostream> #include <memory> #include <atomic>
using namespace std;
template <typename T> class SharedPtr{
public: SharedPtr() : ptr(nullptr), ref_count(new SharedCount()) {}
explicit SharedPtr(T* _ptr) : ptr(_ptr), ref_count(new SharedCount()) {}
SharedPtr(const SharedPtr& _s_ptr) { this->ptr = _s_ptr.ptr; this->ref_count = _s_ptr.ref_count; ref_count->add(); }
SharedPtr& operator=(const SharedPtr& _s_ptr) { clean(); this->ptr = _s_ptr.ptr; this->ref_count = _s_ptr.ref_count; ref_count->add(); return *this; }
SharedPtr(SharedPtr&& _s_ptr) { this->ptr = _s_ptr.ptr; this->ref_count = _s_ptr.ref_count; _s_ptr.ptr = nullptr; _s_ptr.ref_count = nullptr; }
SharedPtr& operator=(SharedPtr&& _s_ptr) { clean(); this->ptr = _s_ptr.ptr; this->ref_count = _s_ptr.ref_count; _s_ptr.ptr = nullptr; _s_ptr.ref_count = nullptr; return *this; }
T* get() const { return ptr; }
T& operator* () const { return *ptr; }
T* operator-> () const { return ptr; }
int use_count() { return ref_count->get(); }
~SharedPtr(){ clean(); }
private: T* ptr; SharedCount* ref_count;
void clean() { if (ref_count) { ref_count->minus(); if (ref_count->get() == 0) { if(ptr) delete ptr; delete ref_count; } } }
};
|
shared_ptr之间有个强制转换static_pointer_cast:具体实现
template<typename T, typename U> SharedPtr<T> static_pointer_cast(const SharedPtr<U>& up) { T* ptr = static_cast<T*>(up.get()); return SharedPtr(up,ptr); }
template<typename U> friend class SharedPtr;
template<typename U> SharedPtr(const SharedPtr<U>& up, T* tp) { this->ptr = tp; this->ref_count = up.ref_count; ref_count->add(); }
|
测试:
class A { public: A() { std::cout << "A() \n"; } ~A() { std::cout << "~A() \n"; } };
class B : public A { public: B() { std::cout << "B() \n"; } ~B() { std::cout << "~B() \n"; } };
void test_shared_ptr() { SharedPtr<size_t> ptr1(new size_t(110)); cout << ptr1.use_count() << endl;
{ SharedPtr<size_t> ptr2 = ptr1; cout << ptr1.use_count() << endl;
SharedPtr<size_t> ptr3(ptr1); cout << ptr1.use_count() << endl;
SharedPtr<size_t> ptr4 = std::move(ptr2); cout << ptr4.use_count() << endl; }
cout << ptr1.use_count() << endl;
}
void test_static_cast() { B* b = new B(); SharedPtr<B> ptr(b); cout << ptr.use_count() << endl; { SharedPtr<A> ptr_a = static_pointer_cast<A,B>(ptr); cout << ptr_a.use_count() << endl; } cout << ptr.use_count() << endl; }
int main(){ test_static_cast(); };
|
unique_ptr
特点:
- 没有引用计数
- 禁止拷贝赋值
#include <iostream>
template<typename T> class unique_ptr { private: T* ptr;
void clean() { if (ptr) { delete ptr; ptr = nullptr; } }
public: unique_ptr() : ptr(nullptr) {}
unique_ptr(T* ptr) : ptr(ptr) {}
unique_ptr(unique_ptr& u_ptr) = delete; unique_ptr& operator=(unique_ptr& u_ptr) = delete;
unique_ptr(unique_ptr&& u_ptr) { this->ptr = u_ptr.ptr; u_ptr.ptr = nullptr; }
unique_ptr& operator=(unique_ptr&& u_ptr) { clean(); this->ptr = u_ptr.ptr; u_ptr.ptr = nullptr; return *this; }
T* get() const { return ptr; }
T* operator->() const { return ptr; }
T& operator*() const { return *ptr; }
~unique_ptr() { clean(); } };
|
weak_ptr
weak_ptr是弱智能指针对象,它不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的智能指针。将一个weak_ptr绑定到一个shared_ptr对象,不会改变shared_ptr的引用计数。一旦最后一个所指向对象的shared_ptr被销毁,所指向的对象就会被释放,即使此时有weak_ptr指向该对象,所指向的对象依然被释放。
void checkwp(weak_ptr<string>& wp) { if (!wp.expired()) { auto sp = wp.lock(); std::cout << *sp << std::endl; } else { std::cout << "wp expired" << std::endl; } }
void test() { shared_ptr<string> sp1 = make_shared<string>("bug maker!");
weak_ptr<string> wp1 = sp1; weak_ptr<string> wp2(sp1); weak_ptr<string> wp3 = wp2;
checkwp(wp1);
wp1.reset(); checkwp(wp1);
checkwp(wp2);
std::cout << (wp2.lock() == wp3.lock() ? "true" : "false") << std::endl; std::cout << (sp1 == wp2.lock() ? "true" : "false") << std::endl;
}
bug maker! wp expired bug maker! true true
|
实现weak_ptr的注意点在于:
- 只能使用shared_ptr和weak_ptr来构造weak_ptr
- 没有自己的数据成员,而是只提供了一些供调用的接口
- 没有重载operator *,operator-> 函数
辅助函数:
- reset 释放被管理对象的所有权。调用后*this不管理对象
- swap 交换被管理对象,只能与其他weak_ptr对象交换。不调整引用计数
- use_count() 返回管理该资源对象的shared_ptr指针对象的数量
- expired() 检直被引用的资源对象是否已删除
- Iock() 创建管理被引用的对象的shared_ptr,是线性安全的
参考: