没有合适的资源?快使用搜索试试~ 我知道了~
C++ unique_ptr weak_ptr shared_ptr auto_ptr智能指针.doc
5星 · 超过95%的资源 需积分: 50 3 下载量 106 浏览量
2021-07-23
18:48:22
上传
评论
收藏 111KB DOC 举报
温馨提示
试读
14页
四种智能指针的使用、机制和缺陷分析
资源详情
资源评论
资源推荐
转自:hps://zhuanlan.zhihu.com/p/54078587?from_voters_page=true
内存管理是 C++中的一个常见的错误和 bug 来源。在大部分情形中,这些
bug 来自动态分配内存和指针的使用:当多次释放动态分配的内存时,可能会
导致内存损坏或者致命的运行时错误;当忘记释放动态分配的内存时,会导致
内存泄露。所以,我们需要智能指针来帮助我们管理动态分配的内存。其来源
于一个事实:栈比堆要安全的多,因为栈上的变量离开作用域后,会自动销毁
并清理。智能指针结合了栈上变量的安全性和堆上变量的灵活性。
指针
形式
auto_ptr unique_ptr shared_ptr weak_ptr
机制
转移对象所有权 仅有一个实例拥有内存所
有权
通过计数器管理引用同一
个指针的指针实例对象的
个数
实现多个对象共享同
一块内存,不拥有这
块内存和计数,也不
会阻止
std::shared_ptr 释放
其内存
缺陷
对象赋值为浅拷
贝,操作结束后
资源将被销毁,
解引用的变量可
能是空指针了,
导致程序崩溃
只有一个实例指向内存 多个内存使用同一块内存
时析构多次,容易造成程
序崩溃,容易出现死锁
“循环引用”
使用
方法
std::unique_ptr<Class
Name> Object1;
auto
Object2=std::make_u
nique<Fraction>(2,
7);
Object1=Object2;
std::shared_ptr<Class
Name>Object1{ par
aments};
auto
Object2=std::make_s
hared<ClassName>()
;
Object1 =Object2;
std::weak_ptr<Clas
sName>Object1{
paraments};
auto
Object2=std::make
_shared<ClassNam
e>();
Object1 =Object2;
注意
事项
尽量使用 make_unique 杜绝死锁的出现
引言
考虑下面一个函数:
void someFunction(){
Resource* ptr = new Resource; // Resource 是一个类或者结构 //
使用 ptr 处理 // ... delete ptr;}
代码很简单:申请了一份动态内存,使用之后释放了它。但是我们很容易会在
函数结束前释放它。也许我们记得及时释放动态申请的内存,但是仍然有一些
不可抗力导致内存无法得到释放,比如函数提前终止了。考虑下面的代码:
void someFunction(){
Resource* ptr = new Resource; // Resource 是一个类或者结构
int x;
std::cout << "Enter an integer: ";
std::cin >> x;
if (x == 0)
return; // 函数终止,无法释放 ptr if (x < 0)
throw; // 出现异常,函数终止,无法释放 ptr // 使用 ptr 处理
// ... delete ptr;}
此时,由于过早的 return 语句以及异常的抛出,ptr 将得不到正确释放,从而出
现内存泄露。归根到底,指针并没有一个内在机制来自动管理与释放。然后,
你可能想到了类:类内部存储指针,然后在析构函数中销毁该指针。类可以实
现资源的自动管理。其好处是,只要类局部变量(分配在栈上)超出其作用域
(不论其是如何离开的),其析构函数一定会被执行,那么管理的内存也将一
定得到销毁。基于这样的想法,我们实现了一个简单的智能指针类:
template<typename T>class Auto_ptr1{public:
Auto_ptr1(T* ptr = nullptr):
m_ptr{ptr}
{}
virtual ~Auto_ptr1()
{
delete m_ptr;
}
T& operator*() { return *m_ptr; }
T* operator->() { return m_ptr; }private:
T* m_ptr;};
class Resource{public:
Resource() { cout << "Resource acquired!" << endl; }
virtual ~Resource() { cout << "Resource destoryed!" <<
endl; }};int main(){
{
Auto_ptr1<Resource> res(new Resource);
}
cin.ignore(10);
return 0;}
执行上面的程序,我们可以得到下面的输出:
Resource acquiredResource destroyed
看来这样的想法完全可以,我们将动态申请的资源交给一个类变量来保存,由
于类变量在局部作用域,其离开后将会自动调用析构函数,然后释放内存。同
时,不论其是如何离开作用域的,即使出现异常,析构函数一定会被执行,内
存也一定得到释放,因为该类变量是保存在栈上的。
但是上面的实现却有致命的隐患,考虑下面的代码:
int main(){
{
Auto_ptr1<Resource> res1(new Resource);
Auto_ptr1<Resource> res2(res1);
}
cin.ignore(10);
return 0;}
看起来没有问题,但是执行起来,程序会崩溃。因为用 res1 初始化 res2,调用
的是默认复制构造函数,执行的是浅复制。所以,res2 与 res1 内部保存是同一
块内存,当销毁变量时,同一块内存将会被多次释放,程序当然会奔溃。同样
地,下面的代码依然存在同样的问题:
void passByValue(Auto_ptr1<Resource> res){}int main(){
{
剩余13页未读,继续阅读
大酷茬子
- 粉丝: 1
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论10