RAII
Resource Acquisition Is Initialization 资源获取即初始化时机。
原理:利用对象的生命周期来管理资源,对象离开作用域自动调用析构函数。
1、RAII 特征
- 在构造时初始化资源或托管资源
- 析构时释放资源
- 一般表达对象语义,不允许复制或者赋值
- 提供若干访问资源的方法
// RAII类解决堆空间对象的释放问题 template <typename T> class RAII { public: // 通过构造函数托管资源 RAII(T * p) : _p(p) {} // 获取所托管的资源的原生的裸指针 T * get() { return _p; } // 访问资源的方法 T* operator->() { return _p; } T & operator*() { return *_p; } // 重置要托管的指针 void reset(T * p) { if(_p) { delete _p; _p = p; } } ~RAII() { if(_p) { delete _p; } } private: T * _p; }; void test0() { //智能指针(对象)托管指针 RAII<Point> pPoint(new Point(1, 2)); pPoint->print(); (*pPoint).print(); //获取所托管的资源的原生的裸指针 cout << "address:" << pPoint.get() << endl; } int main(void) { test0(); return 0; }
2、对象语义
值语义:可以进行复制控制。
对象语义:不能进行复制控制,两种实现方法。
- 将拷贝构造函数和赋值运算符函数设置为私有(C++11前)
private: //表达对象语义,禁止复制 SafeFile(const SafeFile &); SafeFile & operator=(const SafeFile&);
- 将拷贝构造函数和赋值运算符函数使用
=delete
(C++11标准)
SafeFile(const SafeFile &) = delete; SafeFile & operator=(const SafeFile&) = delete;
例:SafeFile 的实现
//对象语义SafeFile #include <stdio.h> #include <iostream> #include <string> #include <fstream> using std::cout; using std::endl; using std::string; using std::ifstream; class SafeFile { public: // 构造函数初始化资源 SafeFile(const string & filename) : _fp(nullptr) { _fp = fopen(filename.c_str(), "a+"); if(!_fp) { cout << "file " << filename << "not found" << endl; } } SafeFile(FILE * fp) : _fp(fp) {} void write(const string & str) { fwrite(str.c_str(), 1, str.size(), _fp); } // 析构时释放资源 ~SafeFile() { if(_fp) { fclose(_fp); cout << "fclose(_fp)" << endl; } } // 2、C++11标准 // 将拷贝构造函数和赋值运算符函数从当前类中删除掉 SafeFile(const SafeFile &) = delete; SafeFile & operator=(const SafeFile&) = delete; private: // 1、C++11标准之前 // 将拷贝构造函数和赋值运算符函数设为私有 // SafeFile(const SafeFile &); // SafeFile & operator=(const SafeFile&); private: FILE * _fp; }; void test0() { // 通过对象来托管文件指针,不需要进行文件指针的回收 // sf对象生命周期被销毁时,会自动调用其析构函数,在析构函数内完成资源回收 SafeFile sf("test.txt"); // 只需要负责对文件指针进行操作即可 sf.write("this is a test line\n"); FILE * fp = nullptr; SafeFile sf2(fp); //sf2 = sf;//error 调用赋值运算符函数 //SafeFile sf3 = sf;//error 调用拷贝构造函数 } void test1() { // C++的所有流对象都是不能进行复制的,表达对象语义(客观对象都是独一无二的) ifstream ifs("test.txt"); ifstream ifs2 = ifs; //调用拷贝构造函数 } int main(void) { test0(); return 0; }