近期正在进行《Effective C++》的第二遍阅读,书里面多个条款涉及到了shared_ptr智能指针,介绍的太分散,学习起来麻烦。写篇blog整理一下。

LinJM   @HQU

shared_ptr是一个智能指针。在C++ 11颁布之前,它包括在TR1(Technical Report 1)其中,如今囊括在C++11的标准库中。

智能指针

智能指针(Smart pointers)是存储“指向动态分配(在堆上)的对象的指针”的对象。也就是说。智能指针事实上是个对象。只是它的行为非常像C++的内建指针,仅仅是它们能够在适当的时候自己主动删除它们所指向的对象。智能指针在面对异常时有非常显著的作用,它们能够确保动态分配对象的全然析构。它们还能够用于跟踪多主人共享的动态分配对象。

在概念上,智能指针能够看作拥有它所指向的对象,并因此在对象不再须要时负责将它删除。

假设对智能指针的概念还不是非常清晰,再看以下的介绍:

A smart pointer is anabstract data type that simulates a pointer while providing additional features, such as automatic
memory management or bounds checking. These additional features are intended to reduce bugs caused by the misuse of pointers while retaining efficiency. Smart pointers typically keep track of the memory they point to. They may also be used to manage other
resources, such as network connections and file handles.     Misuse of pointers is a major source of bugs.Smart pointers prevent most situations of memory leaks by making the memory deallocation automatic.More generally, they make object destruction
automatic: the object controlled by a smart pointer is automatically destroyed (finalized and then deallocated) when the last (or only) owner of the object is destroyed, for example because the owner is a local variable, and execution leaves the variable's
scope. Smart pointers also eliminate dangling pointers by postponing destruction until the object is no longer in use.



shared_ptr

前面已经说了shared_ptr是个智能指针。类似于vector。智能指针也是模板。因此,当我们创建一个智能指针时,必须提供额外的信息——指针能够指向的类型。与vector一样,我们在尖括号内给出类型,之后是所定义的这样的智能指针的名字:

shared_ptr<string> p1;     // shared_ptr,能够指向string
shared_ptr<list<int>> p2; // shared_ptr,能够指向int的list

默认初始化的智能指针中保存着一个空指针。

智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。

假设在一个条件推断中使用智能指针,效果就是检測它是否为空:

//假设p1不为空,检查它是否指向一个空string
if (p1 && p1->empty())
*p1 = "hi"; // 假设p1指向一个空string,解引用p1。将一个新值赋予string

以下列出shared_ptr支持的操作:

shared_ptr<T> p 空智能指针。能够指向类型为T的对象
p 将p用作一个条件推断,若p指向一个对象,则为true
*p 解引用p,获得它所指向的对象
p->mem 等价于(*p).mem
p.get()
返回p中保存的指针。

要小心使用。若智能指针释放了其对象,返回指针所指向的对象也就消失了

swap(p,q)或p.swap(q) 交换p和q的指针
make_shared<T>(args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象。使用args初始化此对象
shared_ptr<T> p(q)
p是shared_ptr q的拷贝;此操作会递增q中的计数器。

q中的指针

必须能转化为T*
p=q
p和q都是shared_ptr,所保存的指针必须能相互转换。此操作会
递减p的引用计数,递增q的引用计数
p.unique() 若p.use_count()为1。返回true,否则返回false
p.use_count() 返回与p共享对象的智能指针数量:可能非常慢。主要用于调试

样例:

//p3指向一个值为42的int的shared_ptr
shared_ptr<int> p3 = make_shared<int>(42);
//p4指向一个值为“99999999”的string
shared_ptr<string> p4 = make_shared<string>(10,'9');

以对象管理资源

上面我们对shared_ptr进行了初步的介绍。只是它的长处我们还没開始阐述。shared_ptr的一个重大长处就是它实现了“以对象管理资源”这个资源管理思想。所谓资源就是,一旦使用了它。将来必须还给系统。在C++中最常使用的资源就是动态分配内存(假设你分配内存却从未归还过,那就会导致内存泄漏),主要通过一对运算符来完毕:new,在动态内存中为对象分配空间并返回一个指向该对象的指针。我们能够选择对对象进行初始化。delete,接受一个动态对象的指针。销毁该对象,并释放与之相关联的内存。

动态内存的使用非常easy出现故障,由于确保在正确的时间释放内存是极其困难的。有时候我们会忘记释放内存。在这样的情况下就会产生内存泄漏。有时在尚有指针引用内存的情况下我们就释放了它,在这样的情况下就会产生非法引用内存的指针。

那么,为了更easy(同一时候更安全)地使用动态内存,我们须要使用智能指针类型来管理动态对象。在C++11之前,C++的标准库提供了auto_ptr来管理动态对象,而tr1中提供了shared_ptr。如今C++11新的标准库将tr1的内容包括进去,提供了两种智能指针来管理动态对象,这两种智能指针的差别在于管理底层指针的方式:shared_ptr同意多个指针指向同一个对象。unique_ptr则“独占”所指向的对象。标准库还定义了一个名为weak_ptr的伴随类。它是一种弱引用。指向shared_ptr所管理的对象。这三种类型都定义在memory头文件里。

以下用一个样例来分析资源管理。

如果我们有一个class Investment,当中包括一个函数createInvestment()供应我们某特定的Investment对象:

// 返回指针,指向Investment继承体系内的动态分配对象。调用者有责任删除它。

// 这里为了简化,刻意不写參数
Investment * createInvestment();

一如凝视所言。createInvestment的调用端使用了函数返回的对象后,有责任删除之。如今考虑有个f()函数履行这个责任:

void f()
{
Investment * pInv = createInvestment();
....
delete pInv;
}

这看起来妥当,但在若干情况下f()可能无法删除它得自createInvestment的对象——也许由于“....”区域中一个过早的return语句或者异常返回,这样程序的控制流就绝不会触及delete语句。从而造成内存泄漏。

当然啦。慎重地编敲代码能够防止这一类错误,可是你必须想想。代码可能会在时间渐渐过去后被改动。

一旦软件開始维护,可能有人加入了return语句。

因此,单纯地依赖“f()总是会运行其delete语句”是行不通的。

那我们该怎么办呢?非常easy——以对象管理资源

把资源放进对象内,当控制流离开f( )。该对象的析构函数会自己主动释放那些资源。

void f()
{
std::tr1::shared_ptr<Investment> pInv(createInvestment());
.....
}

这个简单的样例示范了“以对象管理资源”的两个关键想法:

  • 获得资源后立马放进管理对象内。

    以上代码中createInvestment返回的资源被当作其管理者shared_ptr的初值。实际上“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”,由于我们差点儿总是在获得一笔资源后于同一语句内以它初始化某个管理对象。

  • 管理对象运用析构函数确保资源被释放。不论控制流怎样离开区块。一旦对象被销毁其析构函数自然会被自己主动调用。于是资源被释放。

假设能够,我推荐你看看《C++ Primer》5th 的第12章,里面比較系统地介绍了shared_ptr的用法!

!!。假设你想深入了解shared_ptr,那么Ref[6]值得学习。

Refs:

[1] Stanley B.Lippman. C++ Primer 5th 中文版.电子工业出版社, 2013.

[2] Scott Meyers. Effective C++中文版.电子工业出版社, 2011.

[3] Boost C++ libraries:Smart Pointers 智能指针.

[4] Boost C++ libraries:shared_ptr类模板

[5] John M. Dlugosz. Smart Pointers Overview

[6] std::tr1::shared_ptr源代码赏析

[7] Yonat Sharon. Smart Pointers - What, Why, Which?

本文地址:http://blog.csdn.net/linj_m/article/details/25045403

很多其它相关资源 请关注博客:LinJM-机器视觉 微博:林建民-机器视觉

智能指针 shared_ptr 解析的更多相关文章

  1. c/c++ 智能指针 shared_ptr 和 new结合使用

    智能指针 shared_ptr 和 new结合使用 用make_shared函数初始化shared_ptr是最推荐的,但有的时候还是需要用new关键字来初始化shared_ptr. 一,先来个表格,唠 ...

  2. c/c++ 智能指针 shared_ptr 使用

    智能指针 shared_ptr 使用 上一篇智能指针是啥玩意,介绍了什么是智能指针. 这一篇简单说说如何使用智能指针. 一,智能指针分3类:今天只唠唠shared_ptr shared_ptr uni ...

  3. C++智能指针shared_ptr

    shared_ptr 这里有一个你在标准库中找不到的—引用数智能指针.大部分人都应当有过使用智能指针的经历,并且已经有很多关于引用数的文章.最重要的一个细节是引用数是如何被执行的—插入,意思是说你将引 ...

  4. STL源码剖析-智能指针shared_ptr源码

    目录一. 引言二. 代码实现 2.1 模拟实现shared_ptr2.2 测试用例三. 潜在问题分析 你可能还需要了解模拟实现C++标准库中的auto_ptr一. 引言与auto_ptr大同小异,sh ...

  5. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  6. 智能指针shared_ptr

    // 智能指针会自动释放所指向的对象. // shared_ptr的应用场景是:程序需要在多个对象间共享数据 /* 先从应用场景入手吧,说矿工A发现了一个金矿. * 然后矿工A喊来了矿工B,一起开采, ...

  7. 智能指针shared_ptr新特性shared_from_this及weak_ptr

    enable_shared_from_this是一个模板类,定义于头文件<memory>,其原型为: template< class T > class enable_shar ...

  8. C++ 智能指针 shared_ptr

    今天晚上去旁听了C++高级编程的课,其中提到智能指针.第一反映还以为是auto_ptr呢,一听才知道是share_ptr这个.哦,原来是C++11特性.大致的原因是auto_ptr有一点缺陷,而sha ...

  9. 标准库中的智能指针shared_ptr

    智能指针的出现是为了能够更加方便的解决动态内存的管理问题.注:曾经记得有本书上说可以通过vector来实现动态分配的内存的自动管理,但是经过试验,在gcc4.8.5下是不行的.这个是容易理解的,vec ...

随机推荐

  1. ASP.NET - 对URL传递的值进行编码Server.UrlEncode()

    /// <summary> /// 搜索内容 /// </summary> /// <param name="sender"></para ...

  2. linux中怎样设置dhcpd

    linux中怎样设置DHCP  在 linux 以下设置 DHCP一点也不复杂﹐您全部要做的仅仅有一个文件﹕/etc/dhcpd.conf . 以下﹐我用我自己的设置文件来说说怎么改动这个文件﹕  d ...

  3. Servlet的学习之Request请求对象(3)

    本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看R ...

  4. c#中,DataTable 过滤重复行

    虽然网上有很多DataTable过滤重复行的方法,但是本菜还是认为自己写的这个方法最靠谱,这里的参数是传递的DataTable值,返回的是一个已经过滤相同字段StuId,ExamNum的DataTab ...

  5. Spring mvc interceptor配置拦截器,没有登录跳到登录页

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  6. H2内存数据库 支持存储到文件

     准备工作 1.下载JDK(本人下载的版本号为JDK1.7).环境变量设置JAVA_HOME.设置PATH(%JAVA_HOME%\bin%). 2.下载并解压:h2-2014-07-13.zip ...

  7. FastDFS概要

    本篇文章是我上级老大所写. 留在这里为了不弄丢. FastDFS是一款开源的轻量级分布式文件系统 纯C实现,支持Linux, FreeBSD等UNIX系统 类google FS, 不是通用的文件系统, ...

  8. SAP自带的创建报表工具

    SAP自带的工具有quickview和query两个主要的工具,当然还有其他的 quickview和query的区别主要是query支持系统之间的传输,quickview只能是用户的客户端创建使用,不 ...

  9. Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统(转)

    Tair是一个高性能,分布式,可扩展,高可靠的key/value结构存储系统! Tair专为小文件优化,并提供简单易用的接口(类似Map)Tair支持Java和C版本的客户端 Tair is a di ...

  10. win7下让程序默认以管理员身份运行

    在win7中用自己写的程序读取MBR时,突然提示无法对磁盘进行操作,而在xp下并没有这个问题:最后点右键以管理员身份运行才可以正常运行.于是想办法让程序在双击启动时默认以管理员身份运行.具体方法: 1 ...