RAII:Resource Acquisition Is Initialization 资源获取即初始化时机。
原理:利用对象的生命周期来管理资源,对象离开作用域自动调用析构函数。
1.RAII特征
- 在构造时初始化资源或托管资源
- 析构时释放资源
- 一般表达对象语义,不允许复制或者赋值
- 提供若干访问资源的方法
代码示例
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.对象语义
值语义:可以进行复制控制。
对象语义:不能进行复制控制,两种实现方法
//1.将拷贝构造函数和赋值运算符函数设置为私有(C++11前)
private:
//表达对象语义,禁止复制
SafeFile(const SafeFile &);
SafeFile & operator=(const SafeFile&);
//2.将拷贝构造函数和赋值运算符函数使用 =delete(C++11标准)
SafeFile(const SafeFile &) = delete;
SafeFile & operator=(const SafeFile&) = delete;
代码示例
//对象语义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;
}