首页 > 编程语言 >C++:实现RAII机制

C++:实现RAII机制

时间:2023-04-03 12:44:21浏览次数:37  
标签:const RAII rhs nullptr C++ 机制 data ptr

RAII,也称资源获取即初始化,要求资源的有效期与持有资源的对象的生命期严格绑定,不会出现内存泄漏等问题。

我们尝试将指针封装到RAII类中,实现自动析构。

#include <iostream>

using namespace std;

template<typename T>
class RAII {
public:
	RAII() :data(nullptr) {}
	explicit RAII(T* rhs) :data(rhs) {}
	~RAII() {
		delete data;
	}
	T* operator ->() const {
		return data;
	}
private:
	T* data;
};

struct A {
	int x, y, z;
	~A() {
		cout << "~A();" << endl;
	}
};

int main() {
	RAII<A> ptr(new A{ 123, 456, 789 });
	cout << ptr->x << " " << ptr->y << " " << ptr->z << endl;

	return 0;
}

  

此时我们面临一个问题,此时调用以下代码:

RAII<A> ptr(new A{ 123, 456, 789 });
RAII<A> ptr2 = ptr;

ptr和ptr2中的data同时指向了同一个地址,换句话说,同时有了A的所有权。

程序退出时,析构函数会释放两次内存。

我们可以通过move移交所有权,确保只有一个指针指向A,减少进程退出时的内存释放次数。

以下代码禁用了拷贝构造函数:

template<typename T>
class RAII {
public:
	RAII(const RAII<T>&) = delete; //禁用拷贝构造
	RAII(RAII<T>&& rhs) { //万能引用, 支持move
		data = rhs.data;
		rhs.data = nullptr;
	}

	RAII& operator = (const RAII&) = delete;
	void operator = (RAII<T>&& rhs) {
		data = rhs.data;
		rhs.data = nullptr;
	}
};

int main(){
    	RAII<A> ptr(new A{ 123, 456, 789 });
	RAII<A> ptr2 = move(ptr);
}

  

源代码:

#include <iostream>

using namespace std;

template<typename T>
class RAII {
public:
	RAII() :data(nullptr) {}
	RAII(const RAII<T>&) = delete; //禁用拷贝构造
	RAII(RAII<T>&& rhs) { //万能引用, 支持move
		data = rhs.data;
		rhs.data = nullptr;
	}
	explicit RAII(T* rhs) :data(rhs) {}
	~RAII() {
		delete data;
	}

	RAII& operator = (const RAII&) = delete;
	void operator = (RAII<T>&& rhs) {
		data = rhs.data;
		rhs.data = nullptr;
	}

	T* operator ->() const {
		return data;
	}
private:
	T* data;
};

struct A {
	int x, y, z;
	~A() {
		cout << "~A();" << endl;
	}
};

int main() {
	RAII<A> ptr(new A{ 123, 456, 789 });
	cout << ptr->x << " " << ptr->y << " " << ptr->z << endl;

	RAII<A> ptr2 = move(ptr);

	return 0;
}

  执行结果:

123 456 789
~A();

我们看到虚构函数~A()只执行了一次。

关于生命周期相关问题本文章不做讨论。

 

原文:https://zhuanlan.zhihu.com/p/600337719

作者:严格鸽

标签:const,RAII,rhs,nullptr,C++,机制,data,ptr
From: https://www.cnblogs.com/karinto/p/17282748.html

相关文章

  • C++ Primer 第五版 第十一章 练习题编程题目答案
    https://github.com/jzplp/Cpp-Primer-Answer练习11.1map用关键字索引,是一个字典。vector用整数索引,是一个列表。练习11.2list链表vector顺序列表deque双端队列map字典set集合练习11.311.3map单词计数程序代码练习11.411.4去标点map单词计数程序代码练习11.5如果关键......
  • 【已解决】configure: error: C++ compiler cannot create executables
    1.背景 centos7在升级gccconfigure的时候出现的问题A100-01-$build#../configure--prefix=/usr/local/gcc--enable-threads=posix--disable-checking--disable-multilib--enable-languages=c,c++checkingbuildsystemtype...x86_64-pc-linux-gnucheckinghosts......
  • [C/C++] 判断电脑存储模式(大端/小端)
    C语言版本:#include<stdio.h>#include<inttypes.h>intmain(){uint32_tnum=0xaabbccdd;//字节方向:高->低,也就是aa是高字节,dd是低字节uint8_t*point=(uint8_t*)(&num);for(inti=0;i<sizeof(num);++i){......
  • c++ async future get
    #include<chrono>#include<ctime>#include<future>#include<iomanip>#include<iostream>#include<sstream>#include<string>#include<unistd.h>#include<uuid/uuid.h>std::stringget_time_now(){......
  • C++
    同名的namespace(名字空间/命名空间)有自动合并(为了声明和定义可以分开写)在项目中函数名、全局变量、结构、联合、枚举、类,非常有可能名字冲突,而名字空间就对这些逻辑空间划分(不是物理单元划分),为了解决命名冲突,C++之父为防止命名冲突给C++设计一个名注意:namespace(名字空间/......
  • [2022年蓝桥杯C/C++ A组]个人做题记录
    碎碎念欸嘿,鸽了小半年去做了一些不喜欢的事情,但兜兜转转,还是acm最香捏求和题意求\(\sum_{i=1}^n\sum_{j=1}^na_i*a_j(i!=j)\)题解感觉是去年的时候笨人唯一做满分的题……经典前缀和,设\(sum[i]=\sum_{j=i}^na[j]\),答案即为\(\sum_{i=1}^{n-1}a[i]*sum[i+1]\)#definein......
  • C++学习笔记
    char和string的区别字符串string:C++string详解,C++字符串详解(biancheng.net)string是字符串类型,是在C的基础上对字符数组做封装,是一个类,有自己的函数,存的是一个完整的字符串,确实是由字符组成的,但不能认为里面是一个个char数据类型组成的。因而单拎出来里面的字符不能认为是cha......
  • ArrayList和Vector扩容机制
    ArrayList和Vector扩容机制源码(JDK8)探索ArrayList和Vector都是实现了List接口的集合类,元素有序可重复,支持索引;其中ArrayList是线程不安全的,Vector是线程安全的。两者都通过Object类型的数组elementData存放元素;其扩容机制如下:先说结论:ArrayList无参构造时,初始elementData为......
  • 类加载机制-打破双亲委派机制
     1.什么是双亲委派机制双亲委派机制是Java类加载器的一种工作机制,它的主要思想是:如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委托给父类加载器去完成。如果父类加载器还存在父类加载器,则进一步向上委托,依次递归,直到委托到最顶层的启动类加......
  • Java SPI机制简介
    在JDBC4.0版本之前,使用DriverManager获取Connection对象之前都需要通过代码显式地加载驱动实现类,例如:JDBC4.0之后的版本对此做了改进,我们不再需要显式地加载驱动实现类。这得益于Java中的SPI机制,本节我们就来简单地了解SPI机制。SPI(ServiceProviderInterface)是JDK内置的一......