为了解决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. 【云知道】LoadRunner 录制问题集锦

    关键词:各路录制小白汇集于此 虽然知道君对录制不感冒,但总是看到扎堆的人说这些问题,忍不住要站出来了. 百度虽好,帮助了很多小白,但关键是百度并没有排除错误内容,经过历史的几年传播,错的都快变对的了, ...

  2. JavaScript基础知识总结(一)

    当我们接触一种新语言时,首先要先了解它,对它有一定的理论认识. 那么,什么是JavaScript呢? JavaScript是一种脚本语言,由web浏览器进行解释和执行.它包括ECMAScript.DO ...

  3. Android 微信第三方登录(个人笔记)

    今天在写微信登录,花了半天时间搞定.然后写下自己的笔记,希望帮助更多的人...欢迎各位指教. 微信授权登录,官方说的不是很清楚.所以导致有一部分的坑. 微信注册应用平台的应用签名,下载 微信签名生成工 ...

  4. Firebug中调试中的js脚本中中文内容显示为乱码

    Firebug中调试中的js脚本中中文内容显示为乱码 设置 页面 UFT-8 编码没用, 解决方法:点击 "Firebug"工具栏 中的"选项"---" ...

  5. hadoop 2.4 遇到的问题

    不管出什么问题,首先查看日志. 在启动过hadoop的前提下,打开浏览器,输入http://localhost:50070 点击Utilities下的logs,选择hadoop-root-datano ...

  6. WiFi QC 自动测试:ixChariot API初探

    Chariot虽然给我们提供了友好的界面,但是必须使用命令行或者使用它的API才能 实现自动测试.Chariot在安装的时候会让你选择命令行界面组件,在它的安装目录下面有一些工具, 暂时还不知道是干什 ...

  7. 舍弃Nunit拥抱Xunit

    前言 今天与同事在讨论.Net下测试框架的时候,说到NUnit等大多数测试框架的SetUp以及TearDown方法并不是显得那么完美,所以在公司内部的项目中采用了Xunit框架.那么究竟是什么样的原因 ...

  8. ENode简介与各种教学视频资源汇总(要进群这篇文章必看)

    ENode是什么 ENode是一个.NET平台开源的应用开发框架,为开发人员提供了一套完整的基于DDD+CQRS+ES+(in-memory)+EDA架构风格的解决方案. ENode的特色是什么 解决 ...

  9. 透过浏览器看HTTP缓存

    作为前端开发人员,对于我们的站点或应用的缓存机制我们能做的似乎不多,但这些却是与我们关注的性能息息相关的部分,站点没有做任何缓存机制,我们的页面可能会因为资源的下载和渲染变得很慢,但大家都知道去找前端 ...

  10. 如何设计一门语言(七)——闭包、lambda和interface

    人们都很喜欢讨论闭包这个概念.其实这个概念对于写代码来讲一点用都没有,写代码只需要掌握好lambda表达式和class+interface的语义就行了.基本上只有在写编译器和虚拟机的时候才需要管什么是 ...