shared_ptr 的使用及注意事项
1. 声明
#include <boost/shared_ptr.hpp>
class UsersBitmap {
...
}
typedef boost::shared_ptr<UsersBitmap> UsersBitmapPtr;
2. 使用
UsersBitmapPtr login_users_;
UsersBitmapPtr temp_login_users(new UsersBitmap()); //指向对象
login_users_.reset(new UsersBitmap()); //指针指向新的地方
login_users_.reset(); //指针置空
///////////////////////////////////////////////////////////////////////////
////////////////////////////////////
虽然boost.shared_ptr是个非常好的东西,使用它可以使得c++程序不需要考虑内存释放的问题,但是还是有很多必须注意的地方。下面罗列了一些本人在实际工作中经常碰到的使用shared_ptr出问题的几种情况。
1. shared_ptr多次引用同一数据,如下:
{
int* pInt = new int[100];
boost::shared_ptr<int> sp1(pInt);
// 一些其它代码之后…
boost::shared_ptr<int> sp2(pInt);
}
这种情况在实际中是很容易发生的,结果也是非常致命的,它会导致两次释放同一块内存,而破坏堆。
2.使用shared_ptr包装this指针带来的问题,如下:
class tester
{
public:
tester()
~tester()
{
std::cout << "析构函数被调用!\n";
}
public:
boost::shared_ptr<tester> sget()
{
return boost::shared_ptr<tester>(this);
}
};
int main()
{
tester t;
boost::shared_ptr<tester> sp = t.sget(); // …
return 0;
}
也将导致两次释放t对象破坏堆栈,一次是出栈时析构,一次就是shared_ptr析构。若有这种需要,可以使用下面代码。
class tester : public boost::enable_shared_from_this<tester>
{
public:
tester()
~tester()
{
std::cout << "析构函数被调用!\n";
}
public:
boost::shared_ptr<tester> sget()
{
return shared_from_this();
}
};
int main()
{
boost::shared_ptr<tester> sp(new tester);
// 正确使用sp 指针。
sp->sget();
return 0;
}
3. shared_ptr循环引用导致内存泄露,代码如下:
class parent;
class child;
typedef boost::shared_ptr<parent> parent_ptr;
typedef boost::shared_ptr<child> child_ptr;
class parent
{
public:
~parent() {
std::cout <<"父类析构函数被调用.\n";
}
public:
child_ptr children;
};
class child
{
public:
~child() {
std::cout <<"子类析构函数被调用.\n";
}
public:
parent_ptr parent;
};
int main()
{
parent_ptr father(new parent());
child_ptr son(new child);
// 父子互相引用。
father->children = son;
son->parent = father;
return 0;
}
如上代码,将在程序退出前,father的引用计数为2,son的计数也为2,退出时,shared_ptr所作操作就是简单的将计数减1,如果为0则释放,显然,这个情况下,引用计数不为0,于是造成father和son所指向的内存得不到释放,导致内存泄露。
4. 在多线程程序中使用shared_ptr应注意的问题。代码如下:
class tester
{
public:
tester() {}
~tester() {}
// 更多的函数定义…
};
void fun(boost::shared_ptr<tester> sp)
{
// !!!在这大量使用sp指针.
boost::shared_ptr<tester> tmp = sp;
}
int main()
{
boost::shared_ptr<tester> sp1(new tester);
// 开启两个线程,并将智能指针传入使用。
boost::thread t1(boost::bind(&fun, sp1));
boost::thread t2(boost::bind(&fun, sp1));
t1.join();
t2.join();
return 0;
}
这个代码带来的问题很显然,由于多线程同是访问智能指针,并将其赋值到其它同类智能指针时,很可能发生两个线程同时在操作引用计数(但并不一定绝对发生),而导致计数失败或无效等情况,从而导致程序崩溃,如若不知根源,就无法查找这个bug,那就只能向上帝祈祷程序能正常运行。
可能一般情况下并不会写出上面这样的代码,但是下面这种代码与上面的代码同样,如下:
class tester
{
public:
tester() {}
~tester() {}
public:
boost::shared_ptr<int> m_spData; // 可能其它类型。
};
tester gObject;
void fun(void)
{
// !!!在这大量使用sp指针.
boost::shared_ptr<int> tmp = gObject.m_spData;
}
int main()
{
// 多线程。
boost::thread t1(&fun);
boost::thread t2(&fun);
t1.join();
t2.join();
return 0;
}
情况是一样的。要解决这类问题的办法也很简单,使用boost.weak_ptr就可以很方便解决这个问题。第一种情况修改代码如下:
class tester
{
public:
tester() {}
~tester() {}
// 更多的函数定义…
};
void fun(boost::weak_ptr<tester> wp)
{
boost::shared_ptr<tester> sp = wp.lock;
if (sp)
{
// 在这里可以安全的使用sp指针.
}
else
{
std::cout << “指针已被释放!” << std::endl;
}
}
int main()
{
boost::shared_ptr<tester> sp1(new tester);
boost.weak_ptr<tester> wp(sp1);
// 开启两个线程,并将智能指针传入使用。
boost::thread t1(boost::bind(&fun, wp));
boost::thread t2(boost::bind(&fun, wp));
t1.join();
t2.join();
return 0;
}
boost.weak_ptr指针功能一点都不weak,weak_ptr是一种可构造、可赋值以不增加引用计数来管理shared_ptr的指针,它可以方便的转回到shared_ptr指针,使用weak_ptr.lock函数就可以得到一个shared_ptr的指针,如果该指针已经被其它地方释放,它则返回一个空的shared_ptr,也可以使用weak_ptr.expired()来判断一个指针是否被释放。
boost.weak_ptr不仅可以解决多线程访问带来的安全问题,而且还可以解决上面第三个问题循环引用。Children类代码修改如下,即可打破循环引用:
class child
{
public:
~child() {
std::cout <<"子类析构函数被调用.\n";
}
public:
boost::weak_ptr<parent> parent;
};
因为boost::weak_ptr不增加引用计数,所以可以在退出函数域时,正确的析构。
shared_ptr 的使用及注意事项的更多相关文章
- auto_ptr,shared_ptr 智能指针的使用
Q: 那个auto_ptr是什么东东啊?为什么没有auto_array?A: 哦,auto_ptr是一个很简单的资源封装类,是在<memory>头文件中定义的.它使用“资源分配即初始化”技 ...
- 智能指针auto_ptr & shared_ptr
转载:智能指针auto_ptr 很多人听说过标准auto_ptr智能指针机制,但并不是每个人都天天使用它.这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生 ...
- C++面试基础
自己整理了一些常见的面试题,频率挺高的都是,而且感觉这里这些基础的东西都会问,自己过几天也要面试了,所以发上来让大家一起看看,有什么错误的地方望提醒我纠正. 32位数据类型以及sizeof大小. ch ...
- c++ shared_ptr 使用注意事项. 2
1.抛弃临时对象,让所有的智能指针都有名字. 2.类向外传递 this 的 shared_ptr 让类继承 enable_shared_from_this. 然后返回 shared_from_ ...
- c++ shared_ptr 使用注意事项. 1
条款1:不要把一个原生指针给多个shared_ptr管理 int* ptr = new int; shared_ptr<int> p1(ptr); shared_ptr<int> ...
- shared_ptr注意事项
对shared_ptr的Copy构造和Copy赋值,会改变引用计数,但是对shared_ptr中原始资源的Copy构造和Copy赋值,不会改变引用计数.因此存在下面的危险情况: 1.获取资源时,初始化 ...
- shared_ptr 和 unique_ptr
c++11标准废除乐auto_ptr, C++ 标准库智能指针 使用这些智能指针作为将指针封装为纯旧 C++ 对象 (POCO) 的首选项. unique_ptr 只允许基础指针的一个所有者. 除非你 ...
- c/c++ 智能指针 shared_ptr 使用
智能指针 shared_ptr 使用 上一篇智能指针是啥玩意,介绍了什么是智能指针. 这一篇简单说说如何使用智能指针. 一,智能指针分3类:今天只唠唠shared_ptr shared_ptr uni ...
- c++ shared_ptr的使用
shared_ptr.是c++为了提高指针安全性而添加的智能指针,方便了内存管理.功能非常强大,非常强大,非常强大(不单单是shared_ptr,配合week_ptr以及enable_share_fr ...
随机推荐
- Cucumber capybara 每个Scenario登陆一次
hook.rb中添加: After do |scenario| Capybara.current_session.instance_variable_set(:@touched, false)end ...
- 九度oj 1001 A+B for Matrices 2011年浙江大学计算机及软件工程研究生机试真题
题目1001:A+B for Matrices 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:15235 解决:6172 题目描述: This time, you are supposed ...
- Centos7 ftp服务器搭建
1.使用yum安装ftp服务端: yum install -y vsftpd 2.使用yum安装ftp客户端: yum install -y ftp.x86_64 3.开启ftp服务设置开机启动并查看 ...
- win10-查看wifi密码
1:查看pc连接的wifi名称:netsh wlan show profile 2:生成xml文件: netsh wlan export profile name= YJ-PC_Network fo ...
- ngnix优化【转】
nginx的优化 1. gzip压缩优化 2. expires缓存有还 3. 网络IO事件模型优化 4. 隐藏软件名称和版本号 5. 防盗链优化 6. 禁止恶意域名解析 7. 禁止通过IP地址访问网站 ...
- 2017年11月26日 C#流&&窗体对话框
C#流 在顶端加入using System.IO就可以使用流 StreamReder a = new StreamReder();//读取 前面什么都可以 = sr.ReadToEnd();//用法 ...
- 三:Springboot整合Redis
一:springboot整合redis redis版本:3.0.0 运行环境:linux 1.安装redis 1.1安装gcc yum install gcc-c++ 1.2解压redis.3.0.0 ...
- 一、快速构建Springboot应用
1.基本概念 Spring的出现对于企业级应用来说是一个福音,它让企业级应用开发更加地简单.但是随着Spring的不断发展,它也慢慢变得越来越重.即使apache出品的maven工具能够使得项目创建. ...
- 提示"No 'Access-Control-Allow-Origin' header"及Spring 中解决跨域问题
问题描述 No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://12 ...
- 解决vue移动端适配问题
1,先看看网上关于移动端适配讲解 再聊移动端页面适配,rem和vw适配方案! 基础点:rem相对根节点字体的大小.所以不用px; 根字体:字体的大小px; px:你就当成cm(厘米)这样的东西吧: 基 ...