一、RAII(Resource Acquisition Is Initialization)
资源的使用一般经历三个步骤:获取资源、使用资源、销毁资源。但在实际中程序员往往会忘记释放资源,如何让C++跟java一样自动释放资源呢?C++之父给出RAII解决方案,RAII翻译成中文就是“资源获取即初始化”。它利用了C++语言局部对象自动销毁的特性来控制资源的生命周期,所以当我们在使用资源的时候,在构造函数中进行初始化,在析构函数中进行销毁。
二、智能指针原理
1、基本框架
智能指针就是利用了RAII来自动释放资源的。它本质就是一个类模板,可以创建任意的类型的指针对象,当智能指针对象使用完后,就会自动调用析构函数去释放该指针所指向的空间。
下面就是智能指针的基本框架:
template<class T>
class smart_ptr {
public:
smart_ptr(T* _ptr) : ptr(_ptr) {
}
~smart_ptr() {
delete ptr;
ptr = nullptr;
}
private:
T* ptr;
};
2、智能指针的完善
2.1
智能指针的使用跟普通指针类似,可以使用运算符“ * " 和 ” -> "去获得指向的对象,因此,我们就需要在类中重载" * " 和" -> "函数。
template<class T>
class smart_ptr {
public:
smart_ptr(T* _ptr) : ptr(_ptr) {
}
~smart_ptr() {
delete ptr;
ptr = nullptr;
}
T& operator * () {
return *ptr;
}
T* operator -> () {
return ptr;
}
private:
T* ptr;
};
现在,我们可以这么去使用智能指针了:
int main() {
smart_ptr<int> p1 = smart_ptr<int>(new int(1));
smart_ptr<string> p2 = smart_ptr<string>(new string("hello"));
cout << *p1 << endl;
cout << p2->c_str() << endl;
return 0;
}
2.2
到目前为止,我们的smart_ptr中没有定义"拷贝构造函数"和“赋值运算符”,这时我们只能调用全局的“拷贝构造函数”和“赋值运算符”。但很遗憾,这么做程序会报错!
smart_ptr<int> p1(new int(1));
smart_ptr<int> p2(p1);
这是为什么呢?
因为ptr1、ptr2都指向了同一个资源,在程序结束时,ptr1被析构时会去销毁“资源对象”,当ptr2被析构时也会去销毁“资源对象”,所以资源对象会被重复销毁。这时,最简单的做法是把“拷贝构造函数”、“赋值运算符”都给禁掉:
smart_ptr(smart_ptr&) = delete;
smart_ptr<T>& operator = (smart_ptr<T>&) = delete;
这样一个最简单的智能指针就完成了,下面我附上完整的源代码:
template<class T>
class smart_ptr {
public:
smart_ptr(T* _ptr) : ptr(_ptr) {
}
smart_ptr(smart_ptr&) = delete;
smart_ptr<T>& operator = (smart_ptr<T>&) = delete;
~smart_ptr() {
delete ptr;
ptr = nullptr;
}
T& operator * () {
return *ptr;
}
T* operator -> () {
return ptr;
}
private:
T* ptr;
};