1 为什么要引入智能指针
- 如果一块内存被多个指针引用,但其中的一个指针释放且其余的指针并不知道,这样的情况会发生 挂起引用.
- 内存泄露. 在理想情况下,内存申请了又记得释放就可以了.但是往往在申请与释放之间程序可能出问题(异常,中途return,忘记释放),导致内存没有释放.
2 什么是智能指针
- 智能指针是存储指向动态分配(堆)对象指针的类. 用于实现自动正确的销毁动态分配的对象.防止内存泄漏. (自动调用类的析构函数来进行内存的释放)
- 智能指针比较通过的实现方法就是 引用计数 . 就将一个 计数器 和 类指向的对象 相关联. 引用计数会跟踪这个类有多少个对象共享同一个指针.
- 每次 创建类的新对象 时,初始化指针,并将引用计数置为1;
- 当对象作为另一个对象的副本而创建时, 拷贝构造函数 拷贝指针并增加与之对应的引用计数;
- 对一个对象进行赋值时,赋值操作符减少左侧所指向对象的引用计数(如果计数器减少至0,则析构对象).同时呢**,增加右侧**所指对象的引用计数;
- 调用析构函数时,减少引用计数,若为0,则删除对象.
3 常用的指针指针
有4种智能指针: auto_ptr unique_ptr shared_ptr weak_ptr
auto_ptr
- auto_ptr 实现的是资源的独占 就是说 一个对象智能由一个auto_ptr拥有
- 在 赋值 的时候,会转移这个关系.
- 就是在拷贝构造函数的时候需要记性转移
// 关键的拷贝函数,实现独占
template<class U>
AutoPtr& operator=(AutoPtr<U> &ptr) {
if (ptr->m_ptr != this->m_ptr) { // 判断是否是自拷贝.若不是就要将右侧的指针转移到左侧
delete this->m_ptr;
this->m_ptr = ptr->m_ptr;
ptr->release();
}
return *this;
}
unique_ptr
- 一个unique_ptr拥有它指向的对象. 某个时刻只能有一个unique_ptr指向一个给定对象
- unique_ptr必须采用直接初始化
- unique_ptr 不支持拷贝构造函数和赋值操作符重载.
- 实现方法:将 拷贝构造函数 和 赋值操作符重载函数 私有化 .
shared_ptr
- shared_ptr 即使用的引用计数的方法
- 最安全的分配和使用动态内存方法: 调用** make_shared **
- 必须采用直接初始化.
- shared_ptr的 循环引用 可能会造成 内存泄漏
- 指针间构成了一个死锁,这两块内存直到程序结束前都不会被释放
- 指针间构成了一个死锁,这两块内存直到程序结束前都不会被释放
wake_ptr
- 弱指针的一个重要使用场景就是为了 解决共享指针循环引用造成的内存泄漏
- 它并不控制内存的生成期. 而是通过查询,查看指针的内存是否被释放了.只有不被释放的情况下才可以使用.
- 它只引用,不计数. 指向一个 shared_ptr 管理的对象.
- 使用之前需要检查weak_ptr是否为空指针. 有两个好处:
- 对象被析构了 weak_ptr自动等于NULL
- weak_ptr不会让引用计数错乱
实现auto_ptr
// 实现自动指针
template <class T>
class AutoPtr {
public:
// 构造函数
explicit AutoPtr(T* p = NULL) :m_ptr(p) { // NOP }
// 拷贝构造函数
template<class U> AutoPtr(AutoPtr<U> &rhs)
:m_ptr(rhs.release()){ // NOP }
// 析构函数
~AutoPtr() { delete this->m_ptr; }
/// 基本操作: get,release,重置
T* get() const{ return m_ptr; }
T* release() {
T* tmp = this->m_ptr; // 保存原来指针指向
this->m_ptr = NULL; // 将指针置为空
return tmp; // 内存释放由析构函数完成
}
void reset(T* p) {
if (m_ptr != p) {
delete m_ptr;
this->m_ptr = p;
}
}
// 重载操作符
T& operator*() const {
if (m_ptr != NULL) {
return *m_ptr;
}
}
///指针指向
T* operator->() {
return m_ptr;
}
// 关键的拷贝函数,实现独占
template<class U>
AutoPtr& operator=(AutoPtr<U> &ptr) {
if (ptr->m_ptr != this->m_ptr) {
delete this->m_ptr;
this->m_ptr = ptr->m_ptr;
ptr->release();
}
return *this;
}
private:
T* m_ptr;
};
实现 unique_ptr
// 手写unique_ptr
template<class T>
class UniquePtr {
public:
// 构造函数
UniquePtr(T* ptr=NULL) :m_ptr(ptr){
}
T* operator*() {
return *m_ptr;
}
T* operator->() {
return m_ptr;
}
T* release() {
if (m_ptr != NULL) {
T* tmp = m_ptr;
m_ptr = NULL;
return tmp;
}
return NULL;
}
~UniquePtr() {
if (m_ptr) {
delete m_ptr;
m_ptr = NULL;
}
}
private:
UniquePtr(UniquePtr<T> &rhs) {
//禁止拷贝构造函数
}
UniquePtr<T>& operator=(UniquePtr<T> &rhs) {
// 禁止赋值
}
T *m_ptr;
};
实现 shared_ptr
// 手写shared_ptr
template<class T>
class SharedPtr {
public:
// 构造函数
SharedPtr(T* ptr = NULL) :m_ptr(ptr), m_count(NULL) {
if (NULL != m_ptr) { // 不为空,则需要初始化计数器为1
m_count = new int(1);
}
}
// 拷贝构造函数
SharedPtr(const SharedPtr<T>& rhs) :m_ptr(rhs.m_ptr),m_count(rhs.m_count){
if (NULL != m_count) {
++(*m_count); //自增1
}
}
// 重载赋值运算符
SharedPtr& operator = (SharedPtr& rhs) {
*(rhs->m_count)++;
this->~SharedPtr();
this->m_ptr = rhs->m_ptr;
this->m_count = rhs->m_count;
return *this;
}
T operator*() {
return *m_ptr;
}
T* operator->() {
return m_ptr;
}
T* get_ptr() {
renturn m_ptr;
}
~SharedPtr() {
if (NULL != m_count && 0 == --(*m_count)) {
delete m_ptr;
m_ptr = NULL;
delete m_count;
m_count = NULL;
}
}
private:
T* m_ptr; // 内置指针
int* m_count; // 计数器
};