加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
【知识】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(ptr2.release()); // ptr2会失效,ptr4会获得所有权

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

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

用get()获得裸指针以传递(不转移所有权):
T *nptr = ptr3.get(); // 获取裸指针
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不再拥有这个对象
ptr2.reset(); // 此时ptr2也不再拥有这个对象,因此将删除ptr2/ptr4所指的对象

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

用get()获得裸指针以传递(不共享所有权):
T *nptr = ptr3.get(); // 获取裸指针
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):
Other
if (shared_ptr<t> ptr2 = wptr.lock()) // 如果获取所有权成功     ptr2->func(); // 通过获得的shared_ptr使用对象    if (auto ptr2 = wptr.lock()) // 等价写法     ptr2->func();</t>

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

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

来自:计算机科学 / 软件综合
2
新版本公告
~~空空如也
acmilan 作者
9年7个月前 修改于 9年7个月前 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(c.release()); // c会失效,d会获得对象的所有权

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

获取裸指针以传递(方法与unique_ptr相同):
T *nb = b.get(); // 获取裸指针
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作者
9年7个月前 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注册,6年6个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的