为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer)。

  智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈上的变量自动被销毁,智能指针内部保存的内存也就被释放掉了(除非将智能指针保存起来)。

  C++11提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr,使用时需添加头文件<memory>。

  shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。

  1. shared_ptr的基本用法
  • 初始化

  可以通过构造函数、std::make_shared<T>辅助函数和reset方法来初始化shared_ptr:

#include "stdafx.h"
#include <iostream>
#include <future>
#include <thread> using namespace std;
class Person
{
public:
Person(int v) {
value = v;
std::cout << "Cons" <<value<< std::endl;
}
~Person() {
std::cout << "Des" <<value<< std::endl;
} int value; }; int main()
{
std::shared_ptr<Person> p1(new Person());// Person(1)的引用计数为1 std::shared_ptr<Person> p2 = std::make_shared<Person>(); p1.reset(new Person());// 首先生成新对象,然后引用计数减1,引用计数为0,故析构Person(1)
// 最后将新对象的指针交给智能指针 std::shared_ptr<Person> p3 = p1;//现在p1和p3同时指向Person(3),Person(3)的引用计数为2 p1.reset();//Person(3)的引用计数为1
p3.reset();//Person(3)的引用计数为0,析构Person(3)
return ;
}

  注意,不能将一个原始指针直接赋值给一个智能指针,如下所示,原因是一个是类,一个是指针。

    std::shared_ptr<int> p4 = new int();// error

  reset()包含两个操作。当智能指针中有值的时候,调用reset()会使引用计数减1.当调用reset(new xxx())重新赋值时,智能指针首先是生成新对象,然后将就对象的引用计数减1(当然,如果发现引用计数为0时,则析构旧对象),然后将新对象的指针交给智能指针保管。

  • 获取原始指针  
    std::shared_ptr<int> p4(new int());
int *pInt = p4.get();
  • 指定删除器

  智能指针可以指定删除器,当智能指针的引用计数为0时,自动调用指定的删除器来释放内存。std::shared_ptr可以指定删除器的一个原因是其默认删除器不支持数组对象,这一点需要注意。

  2. 使用shared_ptr需要注意的问题

  但凡一些高级的用法,使用时都有不少陷阱。

  • 不要用一个原始指针初始化多个shared_ptr,原因在于,会造成二次销毁,如下所示:

        int *p5 = new int;
    std::shared_ptr<int> p6(p5);
    std::shared_ptr<int> p7(p5);// logic error
  • 不要在函数实参中创建shared_ptr。因为C++的函数参数的计算顺序在不同的编译器下是不同的。正确的做法是先创建好,然后再传入。
    function(shared_ptr<int>(new int), g());
  • 禁止通过shared_from_this()返回this指针,这样做可能也会造成二次析构。
  • 避免循环引用。智能指针最大的一个陷阱是循环引用,循环引用会导致内存泄漏。解决方法是AStruct或BStruct改为weak_ptr。
struct AStruct;
struct BStruct; struct AStruct {
std::shared_ptr<BStruct> bPtr;
~AStruct() { cout << "AStruct is deleted!"<<endl; }
}; struct BStruct {
std::shared_ptr<AStruct> APtr;
~BStruct() { cout << "BStruct is deleted!" << endl; }
}; void TestLoopReference()
{
std::shared_ptr<AStruct> ap(new AStruct);
std::shared_ptr<BStruct> bp(new BStruct);
ap->bPtr = bp;
bp->APtr = ap;
}

智能指针shared_ptr的用法的更多相关文章

  1. C++智能指针shared_ptr

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

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

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

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

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

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

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

  5. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

  6. 智能指针 shared_ptr 解析

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

  7. C++ 智能指针 shared_ptr 分析

    引文: C++对指针的管理提供了两种解决问题的思路: 1.不允许多个对象管理一个指针 2.允许多个对象管理一个指针,但仅当管理这个指针的最后一个对象析构时才调用delete ps:这两种思路的共同点就 ...

  8. 智能指针shared_ptr

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

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

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

随机推荐

  1. Kooboo CMS技术文档之四:Kooboo CMS的站点组成部分

    Kooboo CMS本着功能独立分离的原则,将站点分为三部分组成:用户管理,站点管理和内容数据库管理.各个功能之间既可独立使用,也可以容易组成在一起形成一个完整的系统. 用户管理 管理整个系统内的用户 ...

  2. VS2015在创建项目时的一些注意事项

    一.下面是在创建一个新的项目是我最常用的,现在对他们一一做一个详细的介绍: 1.Win32控制台应用程序我平时编写小的C/C++程序都用它,它应该是用的最多的. 2.名称和解决方案名称的区别:名称是项 ...

  3. EC笔记:第4部分:20、传递引用代替传值

    考虑以下场景: #include <iostream> #include <string> using namespace std; struct Person { strin ...

  4. TYPESDK手游聚合SDK服务端设计思路与架构之二:服务端设计

    在前一篇文中,我们对一个聚合SDK服务端所需要实现的功能作了简单的分析.通过两个主要场景的功能流程图,我们可以看到,作为多款游戏要适配多个渠道的统一请求转发中心,TYPESDK服务端主要需要实现的功能 ...

  5. Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...

  6. MapReduce

    2016-12-21  16:53:49 mapred-default.xml mapreduce.input.fileinputformat.split.minsize 0 The minimum ...

  7. ASP.NET Aries JSAPI 文档说明:AR.Utility

    AR.Utility 文档 1:方法: 名称 说明 queryString function (key) *模拟.NET的Request对象 stringFormat function (str, a ...

  8. Visual Studio Code预览版Ver 0.3.0试用体验

    当你开始阅读这篇文章时,请先不要把Visual Studio Code和.net.Windows联想到一起,因为VS Code是一个跨平台,支持30多种语言的开箱代码编辑器.不管你是.Net.Java ...

  9. 在同一个硬盘上安装多个 Linux 发行版及 Fedora 21 、Fedora 22 初体验

    在同一个硬盘上安装多个 Linux 发行版 以前对多个 Linux 发行版的折腾主要是在虚拟机上完成.我的桌面电脑性能比较强大,玩玩虚拟机没啥问题,但是笔记本电脑就不行了.要在我的笔记本电脑上折腾多个 ...

  10. 常用数据库的驱动程序和Url地址

    常用数据库的驱动程序及JDBC URL: Oracle数据库: 驱动程序包名:ojdbc6.jar 驱动类的名字:oracle.jdbc.driver.OracleDriver JDBC URL:jd ...