【知识】C++11智能指针
acmilan2016/02/12软件综合 IP:天津
Visual Studio 2010 / 2012 / 2013 / 2015支持三个智能指针,用来管理堆对象,不需要造轮子

1. unique_ptr<T> / unique_ptr<T[]>

保有一个堆对象或一个堆对象数组。该对象的生存期和这个变量相同。只可通过move转移,或者通过get获得裸指针。

unique_ptr可通过两种方式初始化:
unique_ptr<T> ptr1(new T);
auto ptr2 = make_unique<T>(); // VC++2013开始支持

可通过move或release()来转移所有权,这会导致原来的失效并变为nullptr:
auto ptr3 = move(ptr1); // ptr1会失效,ptr3会获得所有权
unique_ptr<T> ptr4(XXXXXXXlease()); // ptr2会失效,ptr4会获得所有权

生存期结束时自动删除堆对象,也可赋值nullptr或调用reset()手动删除堆对象:
ptr4 = nullptr; // ptr4所指对象被删除
XXXXXXXset();

可直接以指针语法使用:
ptr3->func();

用get()获得裸指针以传递(不转移所有权):
T *nptr = XXXXXXXt(); // 获取裸指针
func2(nptr); // 传递裸指针

2. shared_ptr<T> / shared_ptr<T[]>

保有一个堆对象或一个堆对象数组,以及一个引用计数。可以共享所有权,也可通过get获得裸指针。

shared_ptr可通过两种方式初始化:
shared_ptr<T> ptr1(new T);
auto ptr2 = make_shared<T>();

可通过赋值来共享所有权所有权:
auto ptr3 = ptr1; // ptr3和ptr1共同拥有一个对象
auto ptr4 = ptr2; // ptr4和ptr2共同拥有一个对象

生存期结束时释放所有权,也可赋值nullptr或调用reset()手动释放所有权,所有权全部被释放后将删除对象:
ptr4 = nullptr; // 此时ptr4不再拥有这个对象
XXXXXXXset(); // 此时ptr2也不再拥有这个对象,因此将删除ptr2/ptr4所指的对象

可直接以指针语法使用:
ptr3->func();

用get()获得裸指针以传递(不共享所有权):
T *nptr = XXXXXXXt(); // 获取裸指针
func2(nptr); // 传递裸指针

3. weak_ptr<T> / weak_ptr<T[]>

引用一个由shared_ptr管理的堆对象,可通过lock()临时获取堆对象的所有权,并返回一个shared_ptr实例。

通过赋值一个shared_ptr来初始化weak_ptr:
shared_ptr<T> ptr1(new T);
weak_ptr<T> wptr = ptr1; // wptr引用了ptr1管理的堆对象

可通过lock()临时获取一个shared_ptr实例,临时获取堆对象的所有权。获取失败则返回shared_ptr<T>(nullptr):
<code class="lang-cpp">if (shared_ptr<t> ptr2 = wptr.lock()) // 如果获取所有权成功
    ptr2->func(); // 通过获得的shared_ptr使用对象
   
if (auto ptr2 = wptr.lock()) // 等价写法
    ptr2->func();</t></code>

也可以通过它初始化shared_ptr,临时获取堆对象的所有权。获取失败则抛出bad_weak_ptr异常:
<code class="lang-cpp">try{
    shared_ptr<t> ptr2(wptr);
}
catch (bad_weak_ptr&)
{
    printf("bad_weak_ptr\n");
}</t></code>

[修改于 8年10个月前 - 2016/02/13 02:03:05]

来自:计算机科学 / 软件综合
2
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
8年10个月前 修改于 8年10个月前 IP:山东
808390
C++98中的替代物

1. auto_ptr<T>

它是unique_ptr的前身,对堆对象的管理方法与unique_ptr是一样的,但是允许直接赋值来转移所有权,不支持管理数组。

初始化:
auto_ptr<T> a(new T);
auto_ptr<T> c(new T);

转移所有权(赋值也会使得所有权转移,原指针失效,要特别注意这一点):
auto_ptr<T> b = a; // a会失效,b会获得对象的所有权(auto_ptr特有的方式,因容易误用,unique_ptr中被废弃)
auto_ptr<T> d(XXXXlease()); // c会失效,d会获得对象的所有权

可直接以指针语法使用:
b->func();

获取裸指针以传递(方法与unique_ptr相同):
T *nb = XXXXt(); // 获取裸指针
func2(nb); // 传递裸指针

为了避免误用赋值导致指针意外失效,可以将auto_ptr声明为const以阻止赋值操作:
const auto_ptr<T> f(new T); // 阻止赋值操作
const auto_ptr<T> g = f; // 编译错误

由于赋值会导致原指针失效,因此auto_ptr也不能用于STL容器或STL算法:
vector<auto_ptr<T>> vec1; // 错误的用法!!!

由于C++98并不支持模板的数组语法,因此auto_ptr不能包含数组。
否则数组会被delete删除,而不是被delete[]删除,只运行了数组第一个元素的析构函数,可能导致内存泄漏。
auto_ptr<T> h(new T[20]); // 错误的用法!!!

在C++98中,数组可以使用vector管理。

2. vector<T>

这个就不用说了吧,路人皆知的C++中数组的替代品,用法太多不可能一一列举,不知道怎么用的看C++ Primer吧。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan作者
8年10个月前 IP:江西
808394
特别提醒

使用智能指针要注意,一个堆对象只能由一个智能指针系统管理,千万不要做如下的事情:
T *a = new T;
shared_ptr<T> b(a);
shared_ptr<T> c(a); // 错误!a指向的堆对象被删除两次

正确的做法是,对象一经创建,应该立即赋值给某个智能指针管理,只能赋值给一个。
如需要共享对象的所有权,应该先初始化一个shared_ptr实例,再将这个实例赋值给另外一个实例:
shared_ptr<T> a(new T); // 先初始化一个shared_ptr实例
shared_ptr<T> b = a; // 再将这个实例赋值给另外一个实例
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}