本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:C++ – RAII机制
原文链接:https://www.stubbornhuang.com/2417/
发布于:2022年11月21日 15:29:22
修改于:2022年11月21日 15:29:22

1 C++ RAII机制
RAII(Resource Acquisition Is Initialization),资源获取即初始化,是一种C++编程技术。在类的构造函数中请求资源,在类的析构函数中释放资源的技术称为资源获取即初始化,简称RAII。
RAII技术可以将每个资源封装到一个类中,其中
- 构造函数负责获取资源并建立所有类的不变量,如果无法完成则抛出异常
- 析构函数负责释放资源
遵循此种技术规范,可以避免在普通代码中分配内存,把资源分配操作隐藏在构造函数与析构函数中,这样可以避免使用裸new和裸delete操作,使得我们的代码避免因为释放资源而导致内存泄漏的问题。
在C++标准库的设计中,譬如std::string
,std::vector
等遵循RAII设计,另外标准库还提供了几个RAII
包装器用于管理用户的资源,
std::unique_ptr
,std::shared_ptr
智能指针管理动态分配的内存,管理由普通指针表示的任何资源;std::lock_guard
,std::unique_lock
,std::shared_lock
用于管理互斥锁;
下面就是一个典型的遵循RAII机制的C++类代码,
#include <iostream>
#include <string>
class Example
{
public:
Example(int size):m_DataSize(size),m_pData(new double[size])
{
for (int i = 0; i < size; ++i)
{
m_pData[i] = 0.0;
}
std::cout << "构造函数初始化资源" << std::endl;
}
virtual~ Example()
{
delete[] m_pData;
m_DataSize = 0;
std::cout << "析构函数释放资源" << std::endl;
}
private:
double* m_pData;
int m_DataSize;
};
int main()
{
Example example(5);
return 0;
}
如果我们不使用RAII机制设计,会造成什么后果呢?我们看以下的代码
#include <iostream>
#include <string>
#include <assert.h>
void test()
{
double size = 10;
double* array = new double[10];
for (int i = 0; i < size; ++i)
{
array[i] = 0.0;
}
assert(size == 11);
delete[] array;
}
int main()
{
test();
return 0;
}
我们在上述代码中声明了一个10个大小的double型数组,然后给它所有的元素初始化为0.0,在test()
函数的最后一行使用delete[] array
使用数组内存,但是在之前我们使用了一个断言assert(size == 11)
必须要让size == 11
,这显然是不对的,那么程序在运行过程中就在assert
就崩溃了,那么也不会调用delete[] array
释放内存,造成内存泄漏。当然这是一个很简单的程序,所以这种问题也比较容易发现,但是当一个复杂的项目有几万行甚至更多行数时,我们往往会忽略这种问题,从而引发严重的内存泄漏。所以我们这样修改下述代码
#include <iostream>
#include <string>
#include <assert.h>
#include <memory>
void test()
{
double size = 10;
double* array = new double[10];
for (int i = 0; i < size; ++i)
{
array[i] = 0.0;
}
std::unique_ptr<double> p(array);
assert(size == 11);
}
int main()
{
test();
return 0;
}
使用一个std::unique_ptr
对裸指针array
进行包装,这样裸指针的声明周期就由智能指针来控制,就可以避免无法释放内存的问题。
当前分类随机文章推荐
- C++ - 动态链接库dll为什么要使用unsigned char作为byte的内部格式 阅读613次,点赞0次
- C++11 - override关键字简要介绍 阅读2015次,点赞0次
- C++ - 智能指针的正确使用方式 阅读473次,点赞0次
- C++ - 使用标准库std::use_facet和std::codecvt进行跨平台gbk与utf8字符集转换 阅读91次,点赞0次
- C++ - Windows/Linux跨平台获取本机CPU核心数 阅读101次,点赞0次
- C++ - 判断本机文件是否存在的方式总结 阅读4555次,点赞0次
- C++ - 判断两个字符串是否相等方法总结 阅读290次,点赞0次
- C++11 - 使用std::chrono计算程序、函数运行时间 阅读2569次,点赞0次
- C++ - std::string输出双引号到字符串 阅读2903次,点赞0次
- C++ - 数组初始化 阅读255次,点赞0次
全站随机文章推荐
- ThreeJS - 如何提升three.js的渲染效果?看完这篇你可能会有启发 阅读2723次,点赞0次
- 资源分享 - GPU Pro 360 - Guide to Mobile Devices 英文高清PDF下载 阅读2213次,点赞0次
- 资源分享 - Digital Modeling of Material Appearance 英文高清PDF下载 阅读1441次,点赞0次
- MindSpore - LeNet5的MindSpore实现 阅读936次,点赞0次
- Python - 读取csv文件和在csv文件写入内容 阅读382次,点赞0次
- Pip - 常用命令(安装,卸载,升级第三方库) 阅读3131次,点赞1次
- 资源分享 - Physics Modeling for Game Programmers 英文高清PDF下载 阅读1553次,点赞0次
- 资源分享 - Digital Image Processing , Second Edition 英文高清PDF下载 阅读1923次,点赞0次
- Duilib - RichEdit作为日志输出控件,更新日志内容后并自动跳到最后一行 阅读2027次,点赞2次
- OpenCV - linux上编译出现undefined reference to `cv::VideoCapture::VideoCapture()'错误 阅读1743次,点赞0次
评论
167