目录
前言
本文介绍了C++中智能指针的原理与实现,基于施磊老师的C++课程。
一、基础知识
智能指针的基本原理:利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放。
#include <iostream>
using namespace std;
template<typename T>
class CSmartPtr {
public:
CSmartPtr(T *ptr = nullptr) : mptr(ptr) {
}
~CSmartPtr() {
delete mptr; }
T& operator*() {
return *mptr; }
/*
返回底层指针,让底层指针调用->运算符
*/
T* operator->() {
return mptr; }
private:
T *mptr;
};
int main()
{
CSmartPtr<int> p(new int);
*p = 20;
class Test {
public:
void func() {
cout << "Test::func()" << endl; }
};
CSmartPtr<Test> ptr(new Test());
// (ptr.operator->())->test();
ptr->func();
return 0;
}
注意不要将智能指针定义到堆上,没有意义,这种情况下智能指针会变成裸指针:
//看似使用智能指针,实际是裸指针
CSmartPtr<int> *p = new CSmartPtr<int>(new int);
二、不带引用计数的智能指针
在上一节的代码中,如果有以下语句:
CSmartPtr<int> p1(new int);
CSmartPtr<int> p2(p1);
那么运行程序时会发生coredump,容易发现发生了浅拷贝问题,即p2和p1指向了同一块内存资源,在出作用域析构时,p2析构释放了一次,p1析构时重复析构就出现了问题。如果按我们之前的处理方式,实现拷贝构造函数:
CSmart(const CSmart& src) {
mptr = new T(*src.mptr);
}
依然会有问题,因为p1和p2指向了不同的资源,在用户看来,p1和p2应当指向同一个资源,这么处理对用户并不友好。
为了解决浅拷贝问题,C++提出了带引用计数的智能指针和不带引用计数的智能指针,我们先介绍带引用计数的智能指针:
1、auto_ptr
auto_ptr的处理是对拷贝构造函数做处理,其做法是在进行拷贝构造时,将原来的指针释放,并将原来的地址赋值给新的指针:
/**
* @brief An %auto_ptr can be constructed from another %auto_ptr.
* @param __a Another %auto_ptr of the same type.
*
* This object now @e owns the object previously owned by @a __a,
* which has given up ownership.
*/
auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) {
}
/**
* @brief Bypassing the smart pointer.
* @return The raw pointer being managed.
*
* You can get a copy of the pointer that this object owns, for
* situations such as passing to a function which only accepts
* a raw pointer.
*
* @note This %auto_ptr no longer owns the memory. When this object
* goes out of scope, nothing will happen.
*/
element_type*
release() throw()
{
element_type* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}