通俗语言介绍:
int main()
{
try
{
pair<string, string>* p1 = new pair<string, string>;
f();//如果在f函数中抛出异常,会直接跳到catch块后面的语句,导致p1资源没有被释放,造成内存泄漏
delete p1;
}
catch (const exception& e)
{
cout << e.what() << endl;
}
//捕获异常后跳转到的位置
return 0;
}
通俗语言介绍:
简介:
RALL的两大好处:
template<class T>
class SmartPtr
{
public:
// RAII
// 资源交给对象管理,对象生命周期内,资源有效,对象生命周期到了,释放资源
// 1、RAII管控资源释放
// 2、像指针一样
//RAII
SmartPtr(T* ptr)
:_ptr(ptr)
{}
~SmartPtr()
{
cout << "delete:" << _ptr << endl;
delete _ptr;
}
//像指针一样,重载*和->
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void f()
{
// 21:15继续
SmartPtr<pair<string, string>> sp1(new pair<string, string>("1111", "22222"));
//div();
SmartPtr<pair<string, string>> sp2(new pair<string, string>);
SmartPtr<pair<string, string>> sp3(new pair<string, string>);
SmartPtr<string> sp4(new string("xxxxx"));
//像指针一样
cout << *sp4 << endl;
cout << sp1->first << endl;
cout << sp1->second << endl;
div();
//有了智能指针来管理,不需要我们手动释放资源
//delete p1;
//cout << "delete:" << p1 << endl;
}
int main()
{
try
{
f();
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
函数运行结果如下所示:可以发现其析构了两次
int main()
{
SmartPtr<string> sp1(new string("xxxxx"));
SmartPtr<string> sp2(new string("yyyyy"));
sp1 =sp2;
return 0;
}
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << this;
cout << " ~A()" << endl;
}
//private:
int _a;
};
int main()
{
// C++98 一般实践中,很多公司明确规定不要用这个
auto_ptr<A> ap1(new A(1));
auto_ptr<A> ap2(new A(2));
// 管理权转移,拷贝时,会把被拷贝对象的资源管理权转移给拷贝对象
// 隐患:导致被拷贝对象悬空,访问就会出问题
auto_ptr<A> ap3(ap1);
// 崩溃
//ap1->_a++;
ap3->_a++;
return 0;
}
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << this;
cout << " ~A()" << endl;
}
//private:
int _a;
};
int main()
{
// C++11 简单粗暴,不让拷贝
unique_ptr<A> up1(new A(1));
unique_ptr<A> up2(new A(2));
unique_ptr<A> up3(up1);//无法拷贝
return 0;
}
引入:
template<class T>
class shared_ptr
{
public:
// RAII
// 像指针一样
shared_ptr(T* ptr = nullptr)
:_ptr(ptr)
,_pcount(new int(1))//动态开辟,不可以静态,因为有可能有多个智能指针类管理不同的资源
{}
~shared_ptr()
{
if (--(*_pcount) == 0) //析构前要判断引用计数
{
cout << "delete:" << _ptr << endl;
delete _ptr;
delete _pcount;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
// sp3(sp1)
shared_ptr(const shared_ptr<T>& sp) //拷贝时,让新的对象的指针成为这个智能指针类管理的指针
:_ptr(sp._ptr)
,_pcount(sp._pcount)
{
++(*_pcount);
}
//解决自己拷贝自己时,引用计数会增加的问题——————>加入一个判断
// sp1 = sp1
shared_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if (_ptr == sp._ptr)
return *this;
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
_ptr = sp._ptr;
_pcount = sp._pcount;
++(*_pcount);
return *this;
}
//涉及到后面与weak_ptr的搭配问题,不让他直接指向资源(防止引用计数增加)
int use_count() const
{
return *_pcount;
}
T* get() const
{
return _ptr;
}
private:
T* _ptr;
int* _pcount; //动态的引用计数
};
class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A(int a = 0)" << endl;
}
~A()
{
cout << this;
cout << " ~A()" << endl;
}
//private:
int _a;
};
int main()
{
// C++11
shared_ptr<A> sp1(new A(1));
shared_ptr<A> sp3(sp1);//拷贝以后
sp1->_a++;
sp3->_a++;//程序不会崩溃
return 0;
}
template<class T>
class shared_ptr
{
public:
// RAII
// 像指针一样
shared_ptr(T* ptr = nullptr)
:_ptr(ptr)
,_pcount(new int(1))//动态开辟,不可以静态,因为有可能有多个智能指针类管理不同的资源
{}
~shared_ptr()
{
if (--(*_pcount) == 0) //析构前要判断引用计数
{
cout << "delete:" << _ptr << endl;
delete _ptr;
delete _pcount;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
// sp3(sp1)
shared_ptr(const shared_ptr<T>& sp) //拷贝时,让新的对象的指针成为这个智能指针类管理的指针
:_ptr(sp._ptr)
,_pcount(sp._pcount)
{
++(*_pcount);
}
//解决自己拷贝自己时,引用计数会增加的问题——————>加入一个判断
// sp1 = sp1
shared_ptr<T>& operator=(const shared_ptr<T>& sp)
{
if (_ptr == sp._ptr)
return *this;
if (--(*_pcount) == 0)
{
delete _ptr;
delete _pcount;
}
_ptr = sp._ptr;
_pcount = sp._pcount;
++(*_pcount);
return *this;
}
int use_count() const
{
return *_pcount;
}
//涉及到后面与weak_ptr的搭配问题,不让他直接指向资源(防止引用计数增加)
T* get() const
{
return _ptr;
}
private:
T* _ptr;
int* _pcount; //动态的引用计数
};
struct Node
{
A _val;
//不能如此使用,因为后面要让_next&_prev指向的都是智能指针的对象,sp1->_next = sp2;会出现类型不匹配的问题
//Node* _next;
//Node* _prev;
//要把节点指针也用智能指针包装一下才可以
shared_ptr<Node> _next;
shared_ptr<Node> _prev;
};
int main()
{
// 循环引用
shared_ptr<Node> sp1(new Node);
shared_ptr<Node> sp2(new Node);
cout << sp1.use_count() << endl;//1
cout << sp2.use_count() << endl;//1
sp1->_next = sp2;
sp2->_prev = sp1;
cout << sp1.use_count() << endl;//1
cout << sp2.use_count() << endl;//1
//进入死循环
return 0;
}
sp1->_next
能够实现,我们让Node的_next&_prev指针都由智能指针托管sp1->_next
或者sp1->_prev
时,本质上是一种拷贝,会导致资源的引用计数增加use_count()
&get()
template<class T>
class shared_ptr
{
//...略去的内容
int use_count() const
{
return *_pcount;
}
T* get() const
{
return _ptr;
}
private:
T* _ptr;
int* _pcount; //动态的引用计数
};
struct Node
{
A _val;
//shared_ptr<Node> _next;
//shared_ptr<Node> _prev;
weak_ptr<Node> _next;
weak_ptr<Node> _prev;
// weak_ptr不参与资源释放的管理的RAII智能指针,专门用来解决shared_ptr循环引用问题
// weak_ptr不增加引用计数,可以访问资源,不参与资源释放的管理
};
template<class T>
class weak_ptr
{
public:
weak_ptr()
:_ptr(nullptr)
{}
//着手点
weak_ptr(const shared_ptr<T>& sp)
:_ptr(sp.get())
{}
weak_ptr<T>& operator=(const shared_ptr<T>& sp)
{
_ptr = sp.get();
return *this;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
int main()
{
// 循环引用
bit::shared_ptr<Node> sp1(new Node);
bit::shared_ptr<Node> sp2(new Node);
cout << sp1.use_count() << endl;
cout << sp2.use_count() << endl;
sp1->_next = sp2;
sp2->_prev = sp1;
cout << sp1.use_count() << endl;
cout << sp2.use_count() << endl;
return 0;
}
引入:
template<class T>
struct DeleteArray
{
void operator()(T* ptr)
{
delete[] ptr;
}
};
int main()
{
//仿函数
shared_ptr<A> sp1(new A[10], DeleteArray<A>());
//lambda表达式
shared_ptr<A> sp2((A*)malloc(sizeof(A)), [](A* ptr) {free(ptr); });
shared_ptr<FILE> sp3(fopen("Test.cpp", "r"), [](FILE* ptr) {
fclose(ptr);
});
//默认是delete
shared_ptr<A> sp4(new A);
return 0;
}