资源管理RAII
RAII是C++之父Bjarne Stroustrup提出的概念,RAII全称是“Resource Acquisition is Initialization”,即 “资源请求即初始化”, 为解决资源管理时异常安全性所使用的资源管理方法。 RAII要求资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配,同时由析构函数完成资源的释放。
使用 C++ 申请的堆内存空间, 需要程序员自己负责管理回收。然而在编程时稍有不小心会很容易造成内存泄漏。smart point 就是 RAII 资源管理方式,通常是用类模板实现,借用类的析构函数来达成自动释放类中指针所指向的内存空间和对象。智能指针有auto_ptr(C++17 已经被正式从C++标准里删除了)、unique_ptr、shared_ptr。
unique_ptr(since c++11) :
代码:
///
/// @file unique_ptr.cc
/// @author yll(1711019653@qq.com)
/// @date 2021-06-03 14:05:33
///
#include <iostream>
#include <algorithm>
#include <memory>
using std::cout;
using std::endl;
//数组类的指针使用的unique_ptr模板的特化版
/**
*
/// unique_ptr for array objects
template<typename _Tp, typename _Dp>
class unique_ptr<_Tp[], _Dp>
{
...
}
*/
template<typename T, typename D = std::default_delete<T> >
class unique_ptr
{
public:
unique_ptr()
:_ptr(nullptr)
{
cout << "construct unique ptr null" << endl;
}
unique_ptr(T* ptr)
:_ptr(ptr)
{
cout << "construct unique ptr" << endl;
}
//c++ 11, 利用移动语义,可以将指针使用权进行转移
unique_ptr(unique_ptr&& other)
{
_ptr = other.release();
}
unique_ptr& operator=(unique_ptr&& other)
{
_ptr = other.release();
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
T* release()
{
T* ptr = _ptr;
_ptr = nullptr;
return ptr;
}
//对外屏蔽复制构造函数和赋值构造函数
//方法一 删除 复制构造函数和赋值构造函数
//unique_ptr(const unique_ptr<T> & ptr) = delete;
//unique_ptr(const unique_ptr<T, D> & ptr) = delete;
//unique_ptr& operator=(const unique_ptr<T, D>& ptr) = delete;
~unique_ptr()
{
_deleter(_ptr);
}
void swap( unique_ptr& other)
{
std::swap(_ptr, other._ptr);
}
protected:
//方法二 注册复制构造函数和赋值构造函数为protected,对外屏蔽
unique_ptr(const unique_ptr<T, D> & ptr)
{
}
unique_ptr& operator=(const unique_ptr<T, D>& ptr)
{}
private:
T * _ptr;
D _deleter;
};
测试代码:
class Test
{
public:
Test()
{
cout << "test" << endl;
}
void Print()
{
cout << "Print Test " << endl;
}
~Test()
{
cout << "~test" << endl;
}
};
template <class T>
struct deleter
{
void operator()(T* ptr) const
{
if(ptr)
{
cout << "deleter " << endl;
delete ptr;
}
}
};
int main(void)
{
using unique_test = ::unique_ptr<Test, deleter<Test> >;
unique_test uPtr(new Test());
uPtr->Print();
//unique_ptr<Test> uPtr2(uPtr);
//uPtr2->Print();
//unique_test uPtr3 = uPtr;
unique_ptr<Test> uPtr4(std::move(uPtr));
return 0;
}
运行结果:
如果将注释部分取消,会出现报错,无法对 unique_ptr 进行复制:
shared_ptr:
unique_ptr 算是一种较为安全的智能指针了。但是,一个对象只能被单个 unique_ptr 所拥有,这显然不能满足所有使用场合的需求。一种常见的情况是,多个智能指针同时拥有一个对象;当它们全部都失效时,这个对象也同时会被删除。这也就是 shared_ptr 了。
多个不同的 shared_ptr 不仅可以共享一个对象,在共享同一对象时也需要同时共享同一个计数。
代码:
template<class T, class D = std::default_delete<T> >
class shared_ptr
{
public:
shared_ptr()
:_ptr(nullptr)
,_uCount(nullptr)
{
cout << "default constructor " << endl;
}
shared_ptr(T* ptr)
:_ptr(ptr)
,_uCount(new size_t(1))
{
cout << " constructor T*" << endl;
}
shared_ptr(T* ptr, D deleter)
:_ptr(ptr)
,_deleter(deleter)
,_uCount(new size_t(1))
{
cout << " constructor T* DD " << endl;
}
shared_ptr(const shared_ptr<T, D> & sharedPtr)
{
if(sharedPtr._ptr)
{
_ptr = sharedPtr._ptr;
_uCount = sharedPtr._uCount;
add_count();
}
}
shared_ptr& operator=(const shared_ptr<T, D> & sharedPtr)
{
if(_ptr == sharedPtr._ptr){ return *this; }
//为了释放之前管理的旧资源
if(*_uCount == 1){
free();
}else{
reduce_count();
}
_ptr = sharedPtr._ptr;
_uCount = sharedPtr._uCount;
add_count();
return *this;
}
void swap(shared_ptr<T, D> & sharedPtr)
{
std::swap(_ptr, sharedPtr._ptr);
std::swap(_uCount, sharedPtr._uCount);
}
void reset(T* ptr)
{
if(*_uCount == 1){
free();
}else{
reduce_count();
}
_ptr = ptr;
_uCount = new size_t(1);
}
T* get() const { return _ptr; }
size_t use_count()const { return *_uCount; }
void print_use_count()
{
cout << *_uCount << endl;
}
~shared_ptr()
{
//Call Deleter
if(*_uCount == 1){
free();
}else{
reduce_count();
print_use_count();
}
}
private:
void reduce_count()
{
if(*_uCount > 0) -- ( *_uCount);
}
void add_count() { ++(*_uCount); }
void free()
{
_deleter(_ptr);
delete _uCount;
}
private:
T* _ptr;
//std::function<void(T*)> _deleter;
D _deleter;
size_t* _uCount ;
};
测试代码:
class Test
{
public:
Test()
{
cout << "test" << endl;
}
void Print()
{
cout << "Print Test " << endl;
}
~Test()
{
cout << "~test" << endl;
}
};
template <class T>
struct deleter
{
void operator()(T* ptr) const
{
if(ptr)
{
cout << "deleter " << endl;
delete ptr;
}
}
};
int main(void)
{
shared_ptr<Test, deleter<Test>> ptr1(new Test());
ptr1.print_use_count();
shared_ptr<Test, deleter<Test>> ptr2(ptr1);
ptr1.print_use_count();
shared_ptr<Test, deleter<Test>> ptr3 = ptr1;
ptr1.print_use_count();
return 0;
}