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