智能指针 - 现代C++新特性总结
C++98中的智能指针通过一个模板类auto_ptr
来实现,new
操作符返回的指针可以交由它来管理,程序员不用再显式的调用delete
,这在一定程度上避免了堆内存忘记释放的问题;不过auto_ptr
有一些缺点,比如拷贝时返回一个左值,不能调用delete[]等。
C++11中废弃了auto_ptr
,改用unique_ptr、shared_ptr、weak_ptr
等智能指针来自动回收堆分配对象,使内存管理更安全,智能指针的使用场景也变得更全面。
unique_ptr和shared_ptr
unique_ptr是唯一性智能指针,无法进行复制,但是可以移动。而shared_ptr是共享性智能指针,采用引用计数,可以拷贝和移动,移动时引用计数不会变化。
Example
#include <memory>
#include <iostream>
using namespace std;
int main()
{
unique_ptr<int> up1(new int(11));
unique_ptr<int> up2 = up1; //不能通过编译
cout << *up1 << endl; //11
unique_ptr<int> up3 = move(up1); //现在p3是数据唯一的unique_ptr智能指针
cout << *up3 << endl; //11
cout << *up1 << endl; //运行时错误
up3.reset(); //显式释放内存
up1.reset(); //不会导致运行时错误
cout << *up3 << endl; //运行时错误
shared_ptr<int> sp1(new int(22));
shared_ptr<int> sp2 = sp1;
cout << *sp1 << endl; //22
cout << *sp2 << endl; //22
sp1.reset();
cout << *sp2 << endl; //22
}
//编译选项:g++ -std=c++11 unique_share.cpp
上例中,指针调用reset成员时,智能指针都可能释放其拥有的堆内存。
从代码中可以看出,unique_ptr和shared_ptr在对所占内存的共享上还是有一定区别的。
unique_ptr不能与其他unique_ptr类型的指针共享所指对象的内存。比如unique_ptr up2 = up1;不能通过编译,由于up1唯一地占有了new分配的堆内存,所以up2无法共享其“所有权”。这种“所有权”仅能通过标准库的move函数来转移。unique_ptr up3 = move(up1)语句中up3通过move函数夺去了up1的“所有权”,后段使用的*up1就会出现运行时错误。
而shared_ptr允许多个智能指针共享地“拥有”同一堆分配对象的内存。与unique_ptr不同的是,一旦一个shared_ptr指针放弃了“所有权”,其他的shared_ptr对对象内存的引用并不会受到影响。上例中的sp2很好说明了这个状况,sp1调用了reset成员,只是使得引用计数的降低,不会导致堆内存的释放。只有在引用计数归零时,shared_ptr才会真正地释放所占有的堆内存的空间。
weak_ptr
弱智能指针,通常指向一个共享性智能指针,当要使用所指向的共享性智能指针时,使用lock方法获取,并验证共享性智能指针的有效性。
Example:
#include <memory>
#include <iostream>
using namespace std;
void Check(weak_ptr<int> &wp)
{
shared_ptr<int> sp = wp.lock(); //转换为shared_ptr<int>
if (sp != nullptr)
cout << "still " << *sp << endl;
else
cout << "pointer is invalid." << endl;
}
int main()
{
shared_ptr<int> sp1(new int(22));
shared_ptr<int> sp2 = sp1;
weak_ptr<int> wp = sp1; //指向shared_ptr<int>所指对象
cout << *sp1 << endl; //22
cout << *sp2 << endl; //22
Check(wp); //still 22
sp1.reset();
cout << *sp2 << endl; //22
Check(wp); //still 22
sp2.reset();
Check(wp); //pointer is invalid
return 0;
}
//编译选项:g++ -std=c++11 weak.cpp
上例中定义了2个shared_ptr——sp1和sp2,而weak_ptr wp同样指向该对象内存。当sp1和sp2有效时,调用wp的lock(),check会输出still 22。当分别调用sp1和sp2的reset()时,会导致堆内存对象的引用计数降为0。一旦引用计数归0,shared_ptr就会释放对内存空间,使之失效。
整个过程中,只有shared_ptr参与了引用计数,而weak_ptr没有影响其指向的内存的引用计数。因此可以验证shared_ptr指针的有效性。
简单情况下,程序员用unique_ptr代替以前使用auto_ptr就可以使用C++11中的智能指针。而shared_ptr及weak_ptr则可用在用户需要引用计数的地方。
智能指针 - 现代C++新特性总结的更多相关文章
- [转]C++智能指针的创建
zero 坐在餐桌前,机械的重复“夹菜 -> 咀嚼 -> 吞咽”的动作序列,脸上用无形的大字写着:我心不在焉.在他的对面坐着 Solmyr ,慢条斯理的吃着他那份午餐,维持着他一贯很有修养 ...
- c++ 智能指针【转载】
zero 坐在餐桌前,机械的重复“夹菜 -> 咀嚼 -> 吞咽”的动作序列,脸上用无形的大字写着:我心不在焉.在他的对面坐着 Solmyr ,慢条斯理的吃着他那份午餐,维持着他一贯很有修养 ...
- C++ | 智能指针初探
智能指针初探 在 c/c++ 语言中有一种特殊的类型--指针类型. 指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量.它可以直接对内存地址中的数据进行操作,是一种非常灵活的变量.指针被誉为 ...
- C++智能指针(auto_ptr)详解
智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足 ...
- Android系统智能指针的设计思路(轻量级指针、强指针、弱指针)
本博客为原创,转载请注明出处,谢谢. 参考博文:Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 C++中最容易出错的地方莫过于指针了,指针问题主要有两类,一是内存泄露,二是无 ...
- C++中的智能指针(auto_ptr)
实际上auto_ptr 仅仅是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势.使用它不必每次都手动调用delete去释放内存.当然有利也有弊,也不是全然完美的. 本 ...
- STL 智能指针
转自: https://blog.csdn.net/k346k346/article/details/81478223 STL一共给我们提供了四种智能指针:auto_ptr.unique_ptr.sh ...
- 【校招面试 之 C/C++】第25题 C++ 智能指针(一)之 auto_ptr
1.智能指针背后的设计思想 我们先来看一个简单的例子: void remodel(std::string & str) { std::string * ps = new std::string ...
- 智能指针 auto_ptr、scoped_ptr、shared_ptr、weak_ptr
什么是RAII? RAII是Resource Acquisition Is Initialization的简称,是C++语言的一种管理资源.避免泄漏的惯用法. RAII又叫做资源分配即初始化,即:定义 ...
随机推荐
- 利用pdb获取未导出符号
BOOL InitSymHandler(HANDLE hProc) { CHAR SymPath[MAX_PATH], CurDir[MAX_PATH]; GetCurrent ...
- 在PowerDesigner中自动生成sqlserver字段备注
在PowerDesigner中自动生成sqlserver字段备注 PowerDesigner是数据库设计人员常用的设计工具,但其自生默认生成的代码并不会生成sqlserver数据库的字段备注说明.在生 ...
- gdb 调试main
gdb 调试main带参数 gdb program start a b c//参数为a b c然后从main函数开始 r a b c//参数为a b c来运行程序
- linux 文件编码问题
iconv -f UTF- -t gb18030 file_input -o file_output 上述命令不一定有用. 大概了解下文件编码,和vim里面的编码情况. 1 字符编码基础知识 字符编码 ...
- 原生js--文档加载时间
onload触发时机:文档和所有的图片都加载完毕 DOMContentLoaded触发时机:文档加载并解析完毕,所有deferred脚本执行完毕.但此时图片和async脚本可能依旧在加载. ready ...
- 原生js--兼容获取窗口滚动条位置和窗口大小的方法
各个浏览器对获取获取窗口滚动条位置和窗口大小没有提供统一的API,以下是对其封装,解决兼容性问题 /** * 获取浏览器视口的大小(显示文档的部分) * */function getViewPort ...
- 深入学习Make命令和Makefile(下)
https://www.zybuluo.com/lishuhuakai/note/209300 make是Linux下的一款程序自动维护工具,配合makefile的使用,就能够根据程序中模块的修改情况 ...
- [转载]几个有趣的Linux命令
本文给大家介绍几个有趣的Linux命令. 1. pv 命令 有时候我们在电影屏幕上看到一些字幕一个个匀速显示出来,像有人在边敲键盘,边显示一样.Linux上的pv命令可以实现这种效果. 默认情况下 ...
- 如何在Computer下添加System Folder
1.创建一个GUID标识该系统目录,比如:{7854FF7A-470F-4D04-9FC5-4CFC7B2A0E89}.下面的操作步骤将全部使用这个示例GUID. 2.打开注册表编辑器(Registr ...
- node path的一些理解笔录
例子假如我们有这样的文件结构: app/ -lib/ -common.js -model -task.js -test.js 执行代码: var path = require("path&q ...