防内涵吧网站源码,包装设计招聘,电子商务网站建设需要多少钱,seo营销策略文章目录 一、智能指针驱动的RAII二、shared_ptr 和 weak_ptr三、如何复制 RAII 对象四、在资源管理类中应该提供对原始资源的访问函数 为了防止忘记调用 delete 造成的内存泄露#xff0c;我们应该尽可能让对象管理资源#xff0c;并且采用 RAII 机制(Resource Acquisition … 文章目录 一、智能指针驱动的RAII二、shared_ptr 和 weak_ptr三、如何复制 RAII 对象四、在资源管理类中应该提供对原始资源的访问函数 为了防止忘记调用 delete 造成的内存泄露我们应该尽可能让对象管理资源并且采用 RAII 机制(Resource Acquisition is Initialize)机制让析构函数负责资源的释放。
一、智能指针驱动的RAII
在cpp11中可以使用unique_ptr 或者 shared_ptr两种智能指针来管理内存。其中 unique_ptr 通过专一所有权来管理 RAII 的对象而shared_ptr通过引用计数来管理。
std::unique_ptr pUniqueInv1(CreateInvestment()); std::unique_ptr pUniqueInv2(std::move(pUniqueInv1)); std::shared_ptr pSharedInv1(CreateInvestment());
std::shared_ptr pSharedInv2(pSharedInv1); / std::shared_ptr pSharedInv2(std::move(pSharedInv1))
std::move(pSharedInv1)返回的是pSharedInv1的右值引用也就是一个std::shared_ptr类型在执行完这句之后pSharedInv1就变成了一个空指针 nullptr而pSharedInv2现在拥有原本属于pSharedInv1 的对象。 请注意在调用std::shared_ptr 的移动构造函数的时候shared_ptr的引用技术不变。
智能指针默认会自动 delete 所持有的对象我们也可以为智能指针指定所管理对象的释放方式删除器deleter):
// void GetRidOfInvestment(Investment*) {}
std::unique_ptrInvestment, decltype(GetRidOfInvestment)* pUniqueInv(CreateInvestment(), GetRidOfInvestment); std::shared_ptr pSharedInv(CreateInvestment(), GetRidOfInvestment);
在这里decltype的作用是:
二、shared_ptr 和 weak_ptr
一个很常见的面试问题是能否使用 weak_ptr来实现 RAII 答案显然是否定的。 首先介绍一下weak_ptr, weak_ptr是一种用于解决 shared_ptr的循环计数死锁的智能指针。一个例子如下
#include memory
#include vectorclass Child;class Parent {
public:std::vectorstd::shared_ptrChild children;void addChild(const std::shared_ptrChild child) {children.push_back(child);}~Parent() {// 析构函数}
};class Child {
public:std::shared_ptrParent parent;Child(const std::shared_ptrParent p) : parent(p) {}~Child() {// 析构函数}
};可以看到 child 和 parent 互相持有对方的shared_ptr, 造成循环引用。 哪怕当这些对象超出作用御的时候他们的析构函数也不会被调用从而导致内存泄露。
为了解决这个问题我们可以使用 weak_ptr 解决循环引用我们可以把 Child 中的shared_ptr 改成 weak_ptr :
class Child {
public:std::weak_ptrParent parent; // 使用 weak_ptr 而非 shared_ptrChild(const std::shared_ptrParent p) : parent(p) {} //这里参数仍然是shapred_ptr 因为 1. shared_ptr weak_ptr 转换是兼容的。 2.确保有一个 shared_ptrParent存在保证 Parent 对象存活。~Child() {// 析构函数}
};三、如何复制 RAII 对象 引用计数 正如 shared_ptr一样对于每一个资源对象的每一次复制就让引用计数 1 每一个对象离开定义域调用析构函数使得引用计数 - 1 直到引用计数为 0 就把资源销毁。 深拷贝 在拷贝的时候不但copy 对象同时 copy 底层资源比如: 请注意在拷贝的时候有三点是非常需要注意的: 1.是否拷贝了底层资源对象 2.是否 handle 了自赋值 3.是否 handle 了异常处理
#includeiostream
#includecstringclass RAIIArray {
public:RAIIArray(const char* str) {if(str) {len_ std::strlen(str) 1;data_ new char[len];strcpy(data_, str);} else {data_ nullptr;len_ 0;}}//Deepcopy for Copy Constructor RAIIArray(const RAIIArray other) { size_ other.size_;if(size_ 0) {data_ new char[size_];std::strcpy(data_, other.data_);} else { data_ nullptr;}}//Deepcopy for operator RAIIArray operator(const RAIIArray other) { //Identity Judgementif(this ! other) {delete data;size other.size;if(size 0) {data new char[size];std::strcpy(data, other.data); } else {data nullptr;size 0;}} return *this;}//You can also use this : first explicit call copy constructor then copy swapRAIIArray operator(const RAIIArray other) { if(this ! other) {RAIIArray temp(other); //显shi 调用了拷贝构造函数swap(*this, other);}return *this;}//use friend to access the private variables in first and second friend void swap( RAIIArray first, RAIIArray second) {using std::swap;swap(first.size, second.size);swap(first.data, second.data);}//Deepcopy with copy-and-swapRAIIArray operator(RAIIArray other) { swap(*this,other);return *this;}}转移底层资源所有权 和std::unique_ptr类似永远保持只有一个对象拥有对资源的管理权当需要复制对象的时候转移资源的管理权。
四、在资源管理类中应该提供对原始资源的访问函数
和所有的智能指针一样stl 中的智能指针也提供了对原始资源的隐藏访问和显示访问 Investment* pRaw pSharedInv.get(); // 显示访问 Investment raw *pSharedInv; //隐式访问 这里pSharedInv是一个 shared_ptr, 指向Investment类型
当我们自己在设计自己的资源管理类的时候也要考虑在提供原始资源访问的同时是使用显示还是隐式方法。 比如: class Font