简要介绍
智能指针是C++11新特性,其特点是:RAII的设计思路,在对象创建时建立资源,在析构时释放资源,从而避免异常机制导致的资源未释放问题。
常用智能指针有
- shared_ptr:共享智能指针,可以使用多个指针指向同一个数据,并维护一个计数器变量,每有一个shared_ptr指向这个数据,计数器变量就加一,反之则减一。当计数器为0时,则delete 数据的指针。
- weak_ptr:弱引用,不增加引用计数,可以用于检测shared_ptr,也可以用于避免循环引用导致资源无法释放的情况。
- unique_ptr:独占资源,负责资源释放。
常用API:
- ->
- *
- get(),返回指针值(建议不要在返回值域做delete操作)
因此,使用如下代码创建智能指针基类BaseSmartPtr,并实现* -> 和 get()。(全文仅代表我自己学习的一个demo,我本人才疏学浅,STL并不是这么做的。并且我的实现是线程不安全的,要实现线程安全,起码需要一个mutex)
template <typename T>
class BaseSmartPtr
{
public:
T &operator*() { return *_ptr; }
T *operator->() { return _ptr; }
T *get() { return _ptr; }
protected:
BaseSmartPtr() {}
BaseSmartPtr(T *ptr) : _ptr(ptr) {}
~BaseSmartPtr() {}
void DeletePtr()
{
if (_ptr != nullptr)
delete _ptr;
_ptr = nullptr;
}
T *_ptr = nullptr;
};
共享指针shared_ptr
实现源码
// 为了方便WeakPtr使用lock函数返回SharedPtr,因此将WeakPtr设置为SharedPtr的友元类。
// 叠甲-1:我个人认为这不是很好的实现,还有一种实现是在BaseSmartPtr中 定义 _ptr _shared_count 和 _weak_count
// 叠甲-2:我在CSDN大部分的博客上看到的实现,都不是很完整,尤其是weakPtr的lock,expired,相比较而言,我觉得一起实现三种指针更加考验一个程序员。
template <typename T>
class WeakPtr;
template <typename T>
class SharedPtr : public BaseSmartPtr<T>
{
public:
friend class WeakPtr<T>;
SharedPtr() : BaseSmartPtr<T>() {}
SharedPtr(T *ptr) : BaseSmartPtr<T>(ptr), _count(new long long(1))
{
std::cout << "T* ptr constructor of SharedPtr." << std::endl;
}
SharedPtr(T *ptr, long long *_count) : BaseSmartPtr<T>(ptr), _count(_count)
{
(*_count)++;
std::cout << "T* and long long *ptr constructor of SharedPtr(designed for WeakPtr)." << std::endl;
}
// copy constructor 拷贝构造函数
SharedPtr(const SharedPtr<T> &sPtr) : BaseSmartPtr<T>(sPtr._ptr), _count(sPtr._count)
{
(*_count)++;
std::cout << "copy constructor of SharedPtr." << std::endl;
}
// move constructor 移动构造函数
SharedPtr(SharedPtr &&other) : BaseSmartPtr<T>(other._ptr), _count(other._count)
{
other._count = nullptr;
other._ptr = nullptr;
std::cout << "move constructor of SharedPtr." << std::endl;
}
// operator = 赋值运算符(左值)
SharedPtr<T> &operator=(SharedPtr &other) noexcept
{
if (this->_ptr != other._ptr)
{
Release();
this->_ptr = other._ptr;
_count = other._count;
++(*_count);
}
std::cout << "operator = of SharedPtr." << std::endl;
return *this;
}
// move operator =
SharedPtr<T> &operator=(SharedPtr &&other) noexcept
{
if (this != &other)
{
Release();
this->_ptr = other._ptr;
_count = other._count;
other._count = nullptr;
other._ptr = nullptr;
}
std::cout << "move operator = of SharedPtr." << std::endl;
return *this;
}
~SharedPtr()
{
std::cout << "~ function of SharedPtr." << std::endl;
Release();
}
long long use_count() { return this->_ptr != nullptr ? *_count : 0; }
void reset(T *ptr = nullptr)
{
if (this->_ptr != ptr)
{
Release();
if (ptr != nullptr)
{
this->_ptr = ptr;
_count = new long long(1);
}
else
{
this->_ptr = nullptr;
_count = nullptr;
}
}
}
protected:
void Release()
{
if (this->_ptr != nullptr) // 在_ptr不为空的情况下,对count--,如果--后count等于0执行函数体内
{
(*_count)--;
if ((*_count) == 0)
{
//
this->DeletePtr();
delete _count;
_count = nullptr;
std::cout << " delete SharedPtr source." << std::endl;
}
}
}
// T *_ptr = nullptr;
long long *_count = nullptr;
};
重点
- 引用计数++的更新;
- 移动构造和移动赋值;
弱引用智能指针weak_ptr
实现源码
template <typename T>
class WeakPtr : public BaseSmartPtr<T>
{
public:
WeakPtr() : BaseSmartPtr<T>() {}
WeakPtr(const SharedPtr<T> &otherShared) : BaseSmartPtr<T>(otherShared._ptr), _count(otherShared._count)
{
std::cout << " WeakPtr constructed from SharedPtr." << std::endl;
}
WeakPtr(const WeakPtr<T> &other) : BaseSmartPtr<T>(other._ptr), _count(other._count)
{
std::cout << " WeakPtr constructed from WeakPtr." << std::endl;
}
WeakPtr<T> &operator=(const WeakPtr<T> &other)
{
std::cout << " WeakPtr oprtator = ." << std::endl;
this->_ptr = other._ptr;
_count = other._count;
return *this;
}
~WeakPtr()
{
std::cout << " deconstructor of WeakPtr." << std::endl;
}
SharedPtr<T> lock()
{
if (*_count > 0)
{
return std::move(SharedPtr<T>(this->_ptr, this->_count));
}
else
return SharedPtr<T>();
}
bool expired()
{
return *(_count) > 0;
}
private:
long long *_count = nullptr;
};
重点
weak_ptr中比较难实现的是 lock函数。(尤其是在我这样的继承结构下,迫不得已使用友元类)
独占智能指针unique_ptr
实现源码
template <typename T>
class UniquePtr : public BaseSmartPtr<T>
{
public:
UniquePtr() : BaseSmartPtr<T>() {}
UniquePtr(T *ptr) : BaseSmartPtr<T>(ptr)
{
std::cout << " T* constructor of UniquePtr" << std::endl;
}
~UniquePtr()
{
if (this->_ptr != nullptr)
{
std::cout << " destructor of UniquePtr and delete corresponding source." << std::endl;
this->DeletePtr();
}
}
// copy constructor and operator = are deleted to avoid copy
UniquePtr(const UniquePtr<T> &other) = delete;
UniquePtr &operator=(const UniquePtr<T> &other) = delete;
UniquePtr(UniquePtr<T> &&other) : BaseSmartPtr<T>(other._ptr)
{
std::cout << "move destructor of UniquePtr." << std::endl;
other._ptr = nullptr;
}
UniquePtr &operator=(UniquePtr<T> &&other) noexcept
{
std::cout << "move operator = of UniquePtr" << std::endl;
if (this != &other)
{
if (this->_ptr != nullptr)
this->DeletePtr();
this->_ptr = other._ptr;
other._ptr = nullptr;
}
return *this;
}
void reset(T *ptr = nullptr)
{
if (this->_ptr != ptr)
{
if (this->_ptr != nullptr)
this->DeletePtr();
this->_ptr = ptr;
}
}
};
重点
由于是独占资源,因此需要将拷贝构造函数和 operator = 设置为 delete;
保留移动赋值和移动 =。
完整代码(包含main测试)
#include <iostream>
namespace MySmartPtr
{
template <typename T>
class BaseSmartPtr
{
public:
virtual T &operator*() { return *_ptr; }
virtual T *operator->() { return _ptr; }
virtual T *get() { return _ptr; }
protected:
BaseSmartPtr() {}
BaseSmartPtr(T *ptr) : _ptr(ptr) {}
~BaseSmartPtr() {}
void DeletePtr()
{
if (_ptr != nullptr)
delete _ptr;
_ptr = nullptr;
}
T *_ptr = nullptr;
};
// 为了方便WeakPtr使用lock函数返回SharedPtr,因此将WeakPtr设置为SharedPtr的友元类。
// 叠甲-1:我个人认为这不是很好的实现,还有一种实现是在BaseSmartPtr中 定义 _ptr _shared_count 和 _weak_count
// 叠甲-2:我在CSDN大部分的博客上看到的实现,都不是很完整,尤其是weakPtr的lock,expired,相比较而言,我觉得一起实现三种指针更加考验一个程序员。
template <typename T>
class WeakPtr;
template <typename T>
class SharedPtr : public BaseSmartPtr<T>
{
public:
friend class WeakPtr<T>;
SharedPtr() : BaseSmartPtr<T>() {}
SharedPtr(T *ptr) : BaseSmartPtr<T>(ptr), _count(new long long(1))
{
std::cout << "T* ptr constructor of SharedPtr." << std::endl;
}
SharedPtr(T *ptr, long long *_count) : BaseSmartPtr<T>(ptr), _count(_count)
{
(*_count)++;
std::cout << "T* and long long *ptr constructor of SharedPtr(designed for WeakPtr)." << std::endl;
}
// copy constructor 拷贝构造函数
SharedPtr(const SharedPtr<T> &sPtr) : BaseSmartPtr<T>(sPtr._ptr), _count(sPtr._count)
{
(*_count)++;
std::cout << "copy constructor of SharedPtr." << std::endl;
}
// move constructor 移动构造函数
SharedPtr(SharedPtr &&other) : BaseSmartPtr<T>(other._ptr), _count(other._count)
{
other._count = nullptr;
other._ptr = nullptr;
std::cout << "move constructor of SharedPtr." << std::endl;
}
// operator = 赋值运算符(左值)
SharedPtr<T> &operator=(SharedPtr &other) noexcept
{
if (this->_ptr != other._ptr)
{
Release();
this->_ptr = other._ptr;
_count = other._count;
++(*_count);
}
std::cout << "operator = of SharedPtr." << std::endl;
return *this;
}
// move operator =
SharedPtr<T> &operator=(SharedPtr &&other) noexcept
{
if (this != &other)
{
Release();
this->_ptr = other._ptr;
_count = other._count;
other._count = nullptr;
other._ptr = nullptr;
}
std::cout << "move operator = of SharedPtr." << std::endl;
return *this;
}
~SharedPtr()
{
std::cout << "~ function of SharedPtr." << std::endl;
Release();
}
long long use_count() { return this->_ptr != nullptr ? *_count : 0; }
void reset(T *ptr = nullptr)
{
if (this->_ptr != ptr)
{
Release();
if (ptr != nullptr)
{
this->_ptr = ptr;
_count = new long long(1);
}
else
{
this->_ptr = nullptr;
_count = nullptr;
}
}
}
protected:
void Release()
{
if (this->_ptr != nullptr) // 在_ptr不为空的情况下,对count--,如果--后count等于0执行函数体内
{
(*_count)--;
if ((*_count) == 0)
{
//
this->DeletePtr();
delete _count;
_count = nullptr;
std::cout << " delete SharedPtr source." << std::endl;
}
}
}
// T *_ptr = nullptr;
long long *_count = nullptr;
};
template <typename T>
class UniquePtr : public BaseSmartPtr<T>
{
public:
UniquePtr() : BaseSmartPtr<T>() {}
UniquePtr(T *ptr) : BaseSmartPtr<T>(ptr)
{
std::cout << " T* constructor of UniquePtr" << std::endl;
}
~UniquePtr()
{
if (this->_ptr != nullptr)
{
std::cout << " destructor of UniquePtr and delete corresponding source." << std::endl;
this->DeletePtr();
}
}
// copy constructor and operator = are deleted to avoid copy
UniquePtr(const UniquePtr<T> &other) = delete;
UniquePtr &operator=(const UniquePtr<T> &other) = delete;
UniquePtr(UniquePtr<T> &&other) : BaseSmartPtr<T>(other._ptr)
{
std::cout << "move destructor of UniquePtr." << std::endl;
other._ptr = nullptr;
}
UniquePtr &operator=(UniquePtr<T> &&other) noexcept
{
std::cout << "move operator = of UniquePtr" << std::endl;
if (this != &other)
{
if (this->_ptr != nullptr)
this->DeletePtr();
this->_ptr = other._ptr;
other._ptr = nullptr;
}
return *this;
}
void reset(T *ptr = nullptr)
{
if (this->_ptr != ptr)
{
if (this->_ptr != nullptr)
this->DeletePtr();
this->_ptr = ptr;
}
}
};
template <typename T>
class WeakPtr : public BaseSmartPtr<T>
{
public:
WeakPtr() : BaseSmartPtr<T>() {}
WeakPtr(const SharedPtr<T> &otherShared) : BaseSmartPtr<T>(otherShared._ptr), _count(otherShared._count)
{
std::cout << " WeakPtr constructed from SharedPtr." << std::endl;
}
WeakPtr(const WeakPtr<T> &other) : BaseSmartPtr<T>(other._ptr), _count(other._count)
{
std::cout << " WeakPtr constructed from WeakPtr." << std::endl;
}
WeakPtr<T> &operator=(const WeakPtr<T> &other)
{
std::cout << " WeakPtr oprtator = ." << std::endl;
this->_ptr = other._ptr;
_count = other._count;
return *this;
}
~WeakPtr()
{
std::cout << " deconstructor of WeakPtr." << std::endl;
}
SharedPtr<T> lock()
{
if (*_count > 0)
{
return std::move(SharedPtr<T>(this->_ptr, this->_count));
}
else
return SharedPtr<T>();
}
bool expired()
{
return *(_count) > 0;
}
private:
long long *_count = nullptr;
};
}
using namespace MySmartPtr;
void TestSharedPtr()
{
std::cout << "--------------------- Test Sharedptr ---------------------------" << std::endl;
SharedPtr<int> sPtr1 = new int(1);
SharedPtr<int> sPtr2 = sPtr1;
SharedPtr<int> sPtr3(sPtr2);
*sPtr1 = 100;
std::cout << "sPtr1:" << *sPtr1 << std::endl;
std::cout << "sPtr2:" << *sPtr2 << std::endl;
std::cout << "sPtr3:" << *sPtr3 << std::endl;
SharedPtr<int> sPtr4(std::move(sPtr3));
sPtr2 = std::move(sPtr4);
}
struct TestStruct
{
int x = 0;
int y = 1;
TestStruct(int a, int b) : x(a), y(b) {}
int count()
{
return x + y;
}
};
void TestUniqueptr()
{
std::cout << "--------------------- Test Uniqueptr ---------------------------" << std::endl;
UniquePtr<int> uPtr1 = new int(1);
// UniquePtr<int> uPtr2(uPtr1); 无法调用
UniquePtr<int> uPtr2 = std::move(uPtr1);
std::cout << *uPtr2 << std::endl;
uPtr1 = std::move(uPtr2);
// UniquePtr<int> uPtr3(std::)
auto i = uPtr1.get();
std::cout << *i << std::endl;
UniquePtr<TestStruct> SUPtr = new TestStruct(10, 11);
std::cout << SUPtr->x << std::endl;
std::cout << SUPtr->y << std::endl;
std::cout << SUPtr->count() << std::endl;
}
void TestWeakPtr()
{
std::cout << "--------------------- Test Weakptr ---------------------------" << std::endl;
SharedPtr<int> sPtr = new int(1);
WeakPtr<int> wPtr1 = sPtr;
WeakPtr<int> wPtr2 = wPtr1;
WeakPtr<int> wPtr3;
wPtr3 = wPtr2;
}
// void
int main()
{
TestSharedPtr();
TestUniqueptr();
TestWeakPtr();
return 0;
}