C++ smart pointers

content

1. Why do you need smart pointers?

2. Memory leak

3. The use and principle of smart pointers


1. Why do you need smart pointers?

1. If the dynamically applied space is not released, there will be a memory leak problem.

2. If there is an exception thrown between malloc and free, it will still cause a memory leak.

2. Memory leak

The concept of memory leak and its harm

Memory leak is the memory that is not released after dynamic development and is no longer used, and the control of this segment of memory is lost, resulting in a waste of space.

The presence of dynamic memory in a long-running program will make the program slower and slower, and eventually freeze.

void MemoryLeaks()
{
// 1.内存申请了忘记释放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.异常安全问题
int* p3 = new int[10];
Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.
delete[] p3;
}

3. The use and principle of smart pointers

RAII

RAII (Resource Acquisition Is Initialization) is a technology that uses the object life cycle to control program resources.

Resources are acquired when the object is constructed , and finally released when the object is destructed .

template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
~SmartPtr()
{
if(_ptr)
delete _ptr;
}
private:
T* _ptr;
};
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int)*n);
SmartPtr<int> sp(tmp);
}
int main()
{
try {
int a[5] = { 4, 5, 2, 3, 1 };
MergeSort(a, 5);
}
catch(const exception& e)
{
cout<<e.what()<<endl;
}
return 0;
}

The principle of smart pointer

The smartptr above can't call it a pointer yet, it also needs to overload ->, * to act like a pointer.

template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
~SmartPtr()
{
if(_ptr)
delete _ptr;
}
T& operator*() {return *_ptr;}//重载*
T* operator->() {return _ptr;}//重载->
private:
T* _ptr;
};
struct Date
{
int _year;
int _month;
int _day;
};
int main()
{
SmartPtr<int> sp1(new int);
*sp1 = 10
cout<<*sp1<<endl;

SmartPtr<int> sparray(new Date);
sparray->_year = 2018;
sparray->_month = 1;
sparray->_day = 1;
}

std :: auto_ptr

The C++98 version provides a smart pointer for auto_ptr.

#include <memory>
class Date
{
public:
Date() { cout << "Date()" << endl;}
~Date(){ cout << "~Date()" << endl;}
int _year;
int _month;
int _day;
};
int main()
{
auto_ptr<Date> ap(new Date);
auto_ptr<Date> copy(ap);
// auto_ptr的问题:当对象拷贝或者赋值后,前面的对象就悬空了
// C++98中设计的auto_ptr问题是非常明显的,所以实际中很多公司明确规定了不能使用auto_ptr
ap->_year = 2018;
return 0;
}
template<class T>//底层实现
class AutoPtr
{
public:
  AutoPtr(T*ptr = NULL)
    :_ptr(ptr)
  {}

  ~AutoPtr()
  {
    if(_ptr)
      delete _ptr;
   }

  AutoPtr(AutoPtr<T>& ap)
  : _ptr(ap._ptr)
  {
    ap._ptr = NULL;
  }//拷贝后,ap与其管理的资源断开联系,避免一块空间被多个对象使用

  AutoPtr<T>& operator=(AutoPtr<T>& ap)
  {
// 检测是否为自己给自己赋值
    if(this != &ap)
    {
// 释放当前对象中资源
      if(_ptr)
        delete _ptr;
// 转移ap中资源到当前对象中
      _ptr = ap._ptr;
      ap._ptr = NULL;
      }
      return *this;
  }
  T& operator*() {return *_ptr;}
  T* operator->() { return _ptr;}
private:
  T* _ptr;
};

std::unique_ptr

A more reliable unique_ptr is provided in C++11

int main()
{
unique_ptr<Date> up(new Date);
// unique_ptr的设计思路非常的粗暴-防拷贝,也就是不让拷贝和赋值。
unique_ptr<Date> copy(ap);
return 0;
}
template<class T>//底层实现
class UniquePtr
{
public:
  UniquePtr(T * ptr = nullptr)
    : _ptr(ptr)
  {}
  ~UniquePtr()
  {
    if(_ptr)
      delete _ptr;
  }
  T& operator*() {return *_ptr;}
  T* operator->() {return _ptr;}
private:
// C++98防拷贝的方式:只声明不实现+声明成私有
  UniquePtr(UniquePtr<T> const &);
  UniquePtr & operator=(UniquePtr<T> const &);
// C++11防拷贝的方式:delete
  UniquePtr(UniquePtr<T> const &) = delete;
  UniquePtr & operator=(UniquePtr<T> const &) = delete;
private:
  T * _ptr;
};

std::shared_ptr

In C++11, a more reliable shared_ptr that supports copying has begun to be provided

int main()
{
// shared_ptr通过引用计数支持智能指针对象的拷贝
shared_ptr<Date> sp(new Date);
shared_ptr<Date> copy(sp);
cout << "ref count:" << sp.use_count() << endl;
cout << "ref count:" << copy.use_count() << endl;
return 0;
}
template <class T>//底层实现
class SharedPtr
{
public:
  SharedPtr(T* ptr = nullptr)
    : _ptr(ptr)
    , _pRefCount(new int(1))
    , _pMutex(new mutex)
  {}

  ~SharedPtr() {Release();}

  SharedPtr(const SharedPtr<T>& sp)
  : _ptr(sp._ptr)
  , _pRefCount(sp._pRefCount)
  , _pMutex(sp._pMutex)
  {
    AddRefCount();
  }
// sp1 = sp2
  SharedPtr<T>& operator=(const SharedPtr<T>& sp)
  {
//if (this != &sp)
    if (_ptr != sp._ptr)
    {
// 释放管理的旧资源
      Release();
// 共享管理新对象的资源,并增加引用计数
      _ptr = sp._ptr;
      _pRefCount = sp._pRefCount;
      _pMutex = sp._pMutex;
      AddRefCount();
    }
    return *this;
}
  T& operator*() {return *_ptr;}
  T* operator->() {return _ptr;}
  int UseCount() {return *_pRefCount;}
  T* Get() { return _ptr; }
  void AddRefCount()
  {
// 加锁或者使用加1的原子操作
    _pMutex->lock();
    ++(*_pRefCount);
    _pMutex->unlock();
  }
private:
  void Release()
  {
    bool deleteflag = false;
// 引用计数减1,如果减到0,则释放资源
    _pMutex.lock();
    if (--(*_pRefCount) == 0)
    {
      delete _ptr;
      delete _pRefCount;
        deleteflag = true;
    }
    _pMutex.unlock();
    if(deleteflag == true)
      delete _pMutex;
  }
private:
  int* _pRefCount; // 引用计数
  T* _ptr; // 指向管理资源的指针
  mutex* _pMutex; // 互斥锁
};

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324304077&siteId=291194637