C++ 标准库智能指针
整理一下c++中shared_ptr,weak_ptr,unique_ptr三种指针的使用案例和注意事项,让程序资源更加案例,在标准库中,需要包含<memory>,在boost库中,
一. 智能指针unique_ptr
与shared_ptr相似,区别在于unique_ptr是独立拥有对象权,因此只有move语言,无拷贝语义,不做其它详述了。
二.智能指针share_ptr
1.基本使用
class Sam
{
public:
Sam(int v):val(v) { }
int32_t val;
~Sam()
{
std::cout << "~sam()" << std::endl;
}
};
//define
std::shared_ptr<Sam> p1(new Sam());
std::shared_ptr<Sam> p2 = std::make_shared<Sam>();
p1.reset(new Sam(300)); //new first, delete second
std::shared_ptr<Sam> p3 = p1; //get the base ptr
Sam* pSam = p1.get(); //modify
(*p1).val = 10000; //cal is 1
bool b = p1.unique(); p1.reset();
2.高级使用
(1)使用shared_ptr<list<T>>类型,调用reset的时候list中的所有的Sam对象都会调用析构函数
std::shared_ptr<std::list<Sam>> lst_ptr( new std::list<Sam>(, ));
std::cout << lst_ptr.get()->size() << std::endl;
lst_ptr.reset();
(2)程序不知道自己需要使用多少对象. 且程序需要在多个对象间共享数据,使用vector<shared_ptr<T>>类型:
std::vector<std::shared_ptr<Sam>> vec_ptr;
std::shared_ptr<Sam> p1(new Sam());
vec_ptr.push_back(p1);
(3)定制自己的删除器:在shared_ptr释放时会自动调用 函数删除器而不是默认的析构函数了:
void Deleter(Sam* obj) {
std::cout << "Deleter" << std::endl;
} std::shared_ptr<Sam> sp(new Sam(10), Deleter);
如果将删除器定义成类,则自由性更大,下面的代码执行后会调用析构函数(简单地使用了delete)
template<typename T>
class Deleter
{
public:
void operator () (T* x) const
{
if (x != NULL)
{
std::cout << __LINE__ << std::endl;
delete x;
x = NULL;
}
}
}; std::shared_ptr<Sam> sp(new Sam(10), Deleter<Sam> {})
3.错误用法
情形一:一个指针同时放入两个shared_ptr,会在第二个shared_ptr释放时引发异常。
pSam = new Sam();
std::shared_ptr<Sam> p4(pSam);
std::shared_ptr<Sam> p5(pSam);
情形二:数据结构形成环的时候,shared_ptr不能正常工作,需要与weak_ptr协作解决此问题,用例如下:
class CB;
class CA; class CA
{
public:
CA() {}
~CA() { std::cout << "~CA()" << std::endl; } void Register(const std::shared_ptr<CB>& sp)
{
m_sp = sp;
} private:
std::shared_ptr<CB> m_sp;
}; class CB
{
public:
CB() {};
~CB() { std::cout << "~CB()" << std::endl; }; void Register(const std::shared_ptr<CA>& sp)
{
m_sp = sp;
} private:
std::shared_ptr<CA> m_sp;
}; std::shared_ptr<CA> spa(new CA);
std::shared_ptr<CB> spb(new CB); spb->Register(spa);
spa->Register(spb); printf("%d\n", spb.use_count()); //
printf("%d\n", spa.use_count()); //
程序结束后,无法释放内存,也没有调用析构函数,智能指针的引用计数都是2,这就是循环引用问题。
情形三:普通类继承 enable_shared_from_this 的错误情况:
class Y : public std::enable_shared_from_this<Y>
{
public:
std::shared_ptr<Y> GetSharePtr()
{
return shared_from_this();
}
};
Y y;
std::shared_ptr<Y> spy = y.GetSharePtr(); // 错误, y 根本不是 new 创建的
Y* y = new Y;
std::shared_ptr<Y> spy = y->GetSharePtr(); // 错误, 问题依旧存在, 程序直接崩溃
std::shared_ptr<Y> spy(new Y);
std::shared_ptr<Y> p = spy->GetSharePtr();
printf("%d\n", p.use_count()); // 2
前两者错误是因为虽然Y由 enable_shared_from_this派生,但智能指针的数据结构并没有因为new Y的操作赋值 。
三. 智能指针weak_ptr
构造和析构不会引起引用计数的增加或减少。没有重载 * 和 -> 但可以使用lock获得一个可用的shared_ptr对象,且在所指对象内存已经无效时,返回指针空值nullptr.
带有的成员函数reset,use_count
std::shared_ptr<Sam> sam_ptr(new Sam());
std::weak_ptr<Sam> sam_wk = sam_ptr; std::shared_ptr<Sam> sp = sam_wk.lock();
if (sp)
{
std::cout << (*sp).val << endl; // 6
}
std::cout << sp.use_count() << std::endl; //2
C++ 标准库智能指针的更多相关文章
- c/c++ 标准库 智能指针( smart pointer ) 是啥玩意儿
标准库 智能指针( smart pointer ) 是啥玩意儿 一,为什么有智能指针??? c++程序员需要自己善后自己动态开辟的内存,一旦忘了释放,内存就泄露. 智能指针可以帮助程序员"自 ...
- 详解 boost 库智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> 源码分析)
一.boost 智能指针 智能指针是利用RAII(Resource Acquisition Is Initialization:资源获取即初始化)来管理资源.关于RAII的讨论可以参考前面的文章.在使 ...
- C++11标准的智能指针、野指针、内存泄露的理解(日后还会补充,先浅谈自己的理解)
1.野指针的概念.成因以及避免 首先,来说说什么是野指针,所谓野指针就是一个指向未申请访问受限的内存区域或者已经删除了的对象的指针. 什么意思呢?就是本来一个指针指向一个对象.一块内存,但是由于程序( ...
- c++ 智能指针(转)
智能指针的使用 智能指针是在 <memory> 标头文件中的 std 命名空间中定义的. 它们对 RAII 或“获取资源即初始化”编程惯用法至关重要. 此习惯用法的主要目的是确保资源获取与 ...
- 现代C++学习笔记之一入门篇:智能指针(C++ 11)
原始指针:通过new建立的*指针 智能指针:通过智能指针关键字(unique_ptr, shared_ptr ,weak_ptr)建立的指针 在现代 C++ 编程中,标准库包含智能指针,该指针用于确保 ...
- 智能指针auto_ptr & shared_ptr
转载:智能指针auto_ptr 很多人听说过标准auto_ptr智能指针机制,但并不是每个人都天天使用它.这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生 ...
- C++ auto_ptr智能指针的用法
C++中指针申请和释放内存通常采用的方式是new和delete.然而标准C++中还有一个强大的模版类就是auto_ptr,它可以在你不用的时候自动帮你释放内存.下面简单说一下用法. 用法一: std: ...
- C++ Pirmer : 第十四章 : 重载运算符与类型转换之函数调用运算符与标准库的定义的函数对象
函数调用运算符 struct test { int operator()(int val) const { return (i > 0 ? i : -i); } }; 所谓的函数调用就是一个类重 ...
- 标准库中的智能指针shared_ptr
智能指针的出现是为了能够更加方便的解决动态内存的管理问题.注:曾经记得有本书上说可以通过vector来实现动态分配的内存的自动管理,但是经过试验,在gcc4.8.5下是不行的.这个是容易理解的,vec ...
随机推荐
- 【转】rails 遇到 Could not find a JavaScript runtime execjs错误(ubuntu)
当我运行 $rails s 遇到下面错误 sudo apt-get install python-software-properties sudo add-apt-repository ppa:chr ...
- I/O---读取txt文件----demo
首先获得一个文件句柄.File file = new File(); file即为文件句柄. 读取甲方的信息:new FileInputStream(file) 目前这个信息已经读进来内存当中了.接下 ...
- Dev控件GridControl实现CheckBox列和ComBox列
1.在sql语句中添加空白行,如select c1,c2 null c3 from xxx; 2.将sql语句查询结果与gdc绑定CmmFrm.BestFitGridViewColumnsWidth( ...
- 第四章 Javac编译原理(待续)
Javac是什么 Javac编译器的基本结构 Javac工作原理分析 设计模式解析之访问者模式
- How to Enabling and Diabling VxDMP devices for use with Oracle ASM
Enable DMP support for ASM to make DMP devices visible to ASM as available disks To make DMP devices ...
- 【新手向】Centos系统文件权限的系统阐述与演示
在linux服务器日常管理中,我们会经常管理查看文件或者文件夹的权限内容以保证服务的正常运行.今天就和大家聊聊文件权限的那些事. 查看文件的权限情况可以用 ll 命令例: ll -d /kid #查看 ...
- 11-24网页基础--Js基础语法
1.运算符 比较运算符(7种):==/===/!=/>/</<=/>= ===(全等于) 2.字符串substring的用法 3.练习题:累加求和(运用Js的方法) 4.进制转 ...
- springmvc 在页面跳转之后 引入文件的路径前面加上了 controller 的映射名
转自:https://zhidao.baidu.com/question/2140453086362943788.html 应该是没有前面的/user的 前端用的是jsp吗,如果是在路径前加${pag ...
- struts1-mapping.getInputForward()与mapping.getInput
转自:https://www.cnblogs.com/azai/archive/2010/06/05/1752416.html 奇怪为什么登陆失败的时候 没有错误提示.这个问题困扰了N久 仔细看了下, ...
- C#如何生成JSON字符串?(序列化对象)
第一章:C#如何拿到从http上返回JSON数据? 第二章:C#如何解析JSON数据?(反序列化对象) 第三章:C#如何生成JSON字符串?(序列化对象) 第四章:C#如何生成JSON字符串提交给接口 ...