shared_ptr
template <typename T>
class Sptr {
public:
//默认构造函数
Sptr()
:ptr(nullptr),
counter(new int(0))
{}
//构造函数
Sptr(T* pIn)
:ptr(pIn),
counter(new int(1))
{}
//析构函数
~Sptr() {
if (ptr != nullptr && -- * counter == 0) {
del();
}
}
//拷贝构造函数
Sptr(const Sptr& sIn)
:ptr(sIn.ptr),
counter(sIn.counter)
{
++*counter;
}
//拷贝赋值运算符
Sptr& operator=(const Sptr& sIn) {
//记得考虑自我赋值
if (this != &sIn) {
if (ptr != nullptr && -- * counter == 0) {
del();
}
ptr = sIn.ptr;
counter = sIn.counter;
++* counter;
}
return *this;
}
//移动构造函数
Sptr(Sptr &&sIn)
:ptr(sIn.ptr),
counter(sIn.counter)
{
sIn.ptr = nullptr;
sIn.counter = nullptr;
}
//移动赋值运算符
Sptr& operator=(Sptr&& sIn) {
if (this != &sIn) {
if (ptr != nullptr && -- * counter == 0) {
del();
}
ptr = sIn.ptr;
counter = sIn.counter;
sIn.ptr = nullptr;
sIn.counter = nullptr;
}
return *this;
}
//reset
void reset() {
if (ptr != nullptr && -- * counter == 0) {
del();
}
}
void reset(T* pIn) {
if (ptr != nullptr && -- * counter == 0) {
del();
}
ptr = pIn;
*counter = 1;
}
//get
T* get() {
return ptr;
}
//*
T& operator*() {
return *ptr;
}
//->
T* operator->() {
return ptr;
}
//unique
bool unique() {
return *counter == 1;
}
//use_count
int use_count() {
return *counter;
}
//swap
void swap(Sptr &sIn) {
swap(*this, sIn);
}
private:
T* ptr;
int* counter;
//析构调用
void del() {
delete ptr;
delete counter;
ptr = nullptr;
counter = nullptr;
}
};
unique_ptr
template <typename T>
class Uptr {
public:
//构造函数
Uptr(T* pIn = nullptr)
:ptr(pIn)
{}
//析构函数
~Uptr() {
if (nullptr == ptr) return;
del();
}
//拷贝构造函数
Uptr(const Uptr&) = delete;
//拷贝赋值运算符
Uptr& operator=(const Uptr&) = delete;
//移动构造函数
Uptr(Uptr&& pIn)
:ptr(pIn.release())
{
}
//移动赋值运算符
Uptr& operator=(Uptr&& uIn) {
if (this != &uIn) {
del();
ptr = uIn.release();
}
return *this;
}
//reset
void reset(T* pIn = nullptr) {
del();
ptr = pIn;
}
//release
T* release() {
T* ret = ptr;
ptr = nullptr;
return ret;
}
//get
T* get() {
return ptr;
}
//swap
void swap(Uptr& uIn) {
swap(*this, uIn);
}
//*
T& operator*() {
return *ptr;
}
//->
T* operator->() {
return ptr;
}
private:
T* ptr;
//析构调用
void del() {
delete ptr;
ptr = nullptr;
}
};
注意
- 注意拷贝构造函数和拷贝赋值符的区别,
Test t = x
用的是拷贝构造函数,t = x
用的是拷贝赋值符
- 定义了移动构造函数或移动赋值符,vsstudio会删除默认的拷贝构造函数和拷贝赋值符,即不自己重新声明就不能使用这两种拷贝函数
- weak_ptr要用shared_ptr初始化,使用前需要检查,换成shared_ptr使用
- shared_ptr的引用计数器是线程安全的,但对象不是线程安全的
- make_shared和make_unique在动态内存分配一个对象并初始化,返回指向对象的相应智能指针
- 作用①:不使用的话,需要进行两次堆内存分配(对象一次,智能指针一次);使用的话,只进行一次堆内存分配
- 作用②:异常安全。假设在函数两个形参都是shared_ptr,实参使用new的形式,执行过程可能是先进行两次new,再利用两个对象对shared_ptr进行初始化。如果new出第一个对象后,第二个new出现异常,那么第一个对象就发生了内存泄漏
- shared_ptr的计数器为什么要用指针:比如用的是int类型计数器,一个函数的形参是shared_ptr,在函数里面用了
new shared_ptr = 参数shared_ptr
做了赋值构造,按道理原shared_ptr的引用计数器需要-1,但是实际上函数调用处的实参shared_ptr不受影响