C++ 11 14 RAII经典用法

系列服务器开发


前言

使用RAII机制的优点
1、不需要显式地释放资源。
2、采用这种方式,对象所需的资源只在其生命期内始终保持有效。

一、RAII是什么?

RAII全程为Resource Acquisition Is Initialization(资源获取即初始化),RAII是C++语法体系中的一种常用的合理管理资源避免出现内存泄漏的常用方法。以对象管理资源,利用的就是C++构造的对象最终会被对象的析构函数销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。

我们在编程使用系统资源时,都必须遵循一个步骤:申请资源→使用资源→释放资源
由于开始时,条件语句返回,忘记释放等都会造成不及时释放资源,造成资源的浪费等问题

如下是通常出现的常见,由于status等于false,提前返回导致delete没有被调用,arr资源就内存泄漏了。

#include <iostream> 
using namespace std; 

int main() 
{ 
    int *arr = new int [10]; 
    // Here, you can use the array 
    bool status = false;
    if(!status){
    	return 0; 
    }
    delete [] arr; 
    arr = nullptr ; 
    return 0; 
}

如何避免此类问题呢?常用的做法就是RAII方式,下面给出简单的例子,在析构的时候,调用资源释放,从而不会造成内存泄漏、死锁等问题。

二、常用RAII的代码示例

RAIII实现代码如下(示例1):

class MyLock
{
public:
    MyLock(){
        _mutex.lock()
        islocked = true;
    }
    ~MyLock(){
    	if(islocked){
    	 	_mutex.unlock();
    	}
        islocked = false;
    }
    bool unLock(){
    	if(islocked){
			_mutex.unlock();
		}
		islocked = false;
    }
private:
	bool islocked = false;
	std::mutex _mutex;
private:
    MyLock( const MyLock &);
    MyLock operator =(const MyLock &);
};

代码如下(示例2):

class RAIIInstance
{
public:
    RAIIInstance(int size){
        mem = new char[size];
        memset(mem,0,size);
        msize = size;
    }
    ~RAIIInstance(){
        if(mem){
            delete mem;
            mem = nullptr
        }
        msize  = 0;
    }
    char *getAddr(){
        return mem;
    }
    bool setValue(char *value,int size){
		if(size > msize ){
			return false;
		}
		memcpy(mem,value,size);
	};
private:
	int msize = 0;
    char * mem=nullptr;
};

RAII 具体使用如下代码

1、c++11 新特性,智能指针即实现了RAII函数,用法如下

代码如下(示例1):

std::shared_ptr<int> sp1(new int(123));

std::shared_ptr<int> sp2;
sp2.reset(new int(123));

std::shared_ptr<int> sp3 = std::make_shared<int>(123);

//分配数组,自定义delete函数
std::shared_ptr<int> ptr(new int[10], 
		[](int* p) {
			delete[]p; 
		}
	);

2、c++11 通过智能指针,指定特定”delete“函数,通过lamda表达式来实现

代码如下(示例2):

std::unique_ptr<FILE,function<void(FILE*)>> ptr2(fopen("data.txt","w"),
		[](FILE*p)->void{
			cout<<"call my lambda deleter:FILE"<<endl;
			fclose(p);
		}
	);

3、c++11 通过RAII 锁机制,析构时释放资源,避免不解锁。

代码如下(示例2):

std::mutex _mutex;
std::lock_guard<std::mutex> guard(_mutex);
std::unique_lock<std::mutex> lock(_mutex);

4、c++11 通过RAII机制,自定义delete函数,释放资源

float * normalizedData = Normalize(mat);       
std::shared_ptr<Request> out;
out.reset(new Request, [normalizedData](Request * p) {
     delete p;
     delete [] normalizedData;
});

总结

RAII机制保证了异常安全,并且也为程序员在编写动态分配内存的程序时提供了安全保证。但它也存在一些缺点,缺点就是有些操作可能会抛出异常,如果放在析构函数中进行则不能将错误传递出去,那么此时析构函数就必须自己处理异常。这在某些时候是很繁琐的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c+猿辅导

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值