笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

C ++库提供以下类型的智能指针的实现:

  • auto_ptr
  • unique_ptr
  • shared_ptr
  • weak_ptr

它们都是在内存头文件中声明。

auto_ptr

从C ++ 11开始,此类模板已被弃用。 unique_ptr是具有相似功能但具有改进的安全性的新工具。
auto_ptr是一个智能指针,用于管理通过新表达式获取的对象,并在auto_ptr本身被销毁时删除该对象。
当使用auto_ptr类描述一个对象时,它存储一个指向单个分配对象的指针,该对象可以确保当它超出范围时,它指向的对象必须被自动销毁。 它基于独占所有权模式,即同一类型的两个指针不能同时指向相同的资源。 如下面的程序所示,复制或分配指针会更改所有权,即源指针必须赋予目标指针所有权。

#include<iostream>
#include<memory>
using namespace std;

class A
{
public:
    void show() {  cout << "A::show()" << endl; }
};

int main()
{
    // p1 is an auto_ptr of type A
    auto_ptr<A> p1(new A);
    p1 -> show();

    // returns the memory address of p1
    cout << p1.get() << endl;

    // copy constructor called, this makes p1 empty.
    auto_ptr <A> p2(p1);
    p2 -> show();

    // p1 is empty now
    cout << p1.get() << endl;

    // p1 gets copied in p2
    cout<< p2.get() << endl;

    return 0;
}

Output:

A::show()
0x1b42c20
A::show()
0
0x1b42c20

auto_ptr的拷贝构造函数和赋值运算符实际上并没有复制存储的指针,而是将它们传输出去,使第一个auto_ptr对象变为空。 这是实现严格所有权的一种方法,因此只有一个auto_ptr对象可以在任何给定时间拥有该指针,即在需要复制语义的情况下不应使用auto_ptr。

unique_ptr

std :: unique_ptr是在C ++ 11中开发的,用于替代std :: auto_ptr。unique_ptr是具有类似功能的新工具,但具有改进的安全性(无假拷贝分配),添加功能(删除器)和数组支持。 它是一个原始指针的容器。 它明确地防止复制其包含的指针,正如正常赋值那样会发生,即它只允许底层指针的一个所有者。
所以,当使用unique_ptr时,在任何一个资源上最多只能有一个unique_ptr,当该unique_ptr被破坏时,该资源将被自动声明。 另外,由于任何资源只能有一个unique_ptr,所以任何创建unique_ptr副本的尝试将导致编译时错误。

 unique_ptr<A> ptr1 (new A);

 // Error: can't copy unique_ptr
 unique_ptr<A> ptr2 = ptr1;

但是,unique_ptr可以使用新的语义,即使用std :: move()函数将包含的指针的所有权转移到另一个unique_ptr。

// Works, resource now stored in ptr2
unique_ptr<A> ptr2 = move(ptr1); 

所以,最好使用unique_ptr,当我们想要一个指向一个对象的指针,当该单个指针被销毁时将被回收。

// C++ program to illustrate the use of unique_ptr
#include<iostream>
#include<memory>
using namespace std;

class A
{
public:
    void show()
    {
        cout<<"A::show()"<<endl;
    }
};

int main()
{
    unique_ptr<A> p1 (new A);
    p1 -> show();

    // returns the memory address of p1
    cout << p1.get() << endl;

    // transfers ownership to p2
    unique_ptr<A> p2 = move(p1);
    p2 -> show();
    cout << p1.get() << endl;
    cout << p2.get() << endl;

    // transfers ownership to p3
    unique_ptr<A> p3 = move (p2);
    p3->show();
    cout << p1.get() << endl;
    cout << p2.get() << endl;
    cout << p3.get() << endl;

    return 0;
}

Output:

A::show()
0x1c4ac20
A::show()
0          // NULL
0x1c4ac20
A::show()
0          // NULL
0          // NULL
0x1c4ac20

下面的代码返回一个资源,如果我们没有显式捕获返回值,资源将被清除。 如果我们这样做,那么我们拥有该资源的独占所有权, 这样我们可以将unique_ptr看作更安全,更好的替换auto_ptr。

unique_ptr<A> fun()
{
    unique_ptr<A> ptr(new A);

    /* ...
       ... */

    return ptr;
}

何时使用unique_ptr?
当您想拥有资源的唯一所有权(Exclusive)时,请使用unique_ptr, 只有一个unique_ptr可以指向一个资源, 因为单个资源可以有一个unique_ptr,所以不可能将一个unique_ptr复制到另一个。

shared_ptr

shared_ptr是原始指针的容器。 它是一个引用计数模型,即它与shared_ptr的所有副本合作维护其包含的指针的引用计数。 因此,每当一个新的指针指向资源时,计数器就会递增,当调用对象的析构函数时递减计数器。

引用计数:这是一种将资源数量,指针或句柄存入资源(如对象,内存块,磁盘空间或其他资源)的技术。

引用计数大于0,直到所有的shared_ptr副本都被删除,所包含的原始指针引用的对象将不会被销毁。因此,当我们要为一个原始指针分配给多个所有者时,我们应该使用shared_ptr。
#include<iostream>
#include<memory>
using namespace std;

class A
{
public:
    void show()
    {
        cout<<"A::show()"<<endl;
    }
};

int main()
{
    shared_ptr<A> p1 (new A);
    cout << p1.get() << endl;
    p1->show();
    shared_ptr<A> p2 (p1);
    p2->show();
    cout << p1.get() << endl;
    cout << p2.get() << endl;

    // Returns the number of shared_ptr objects
    //referring to the same managed object.
    cout << p1.use_count() << endl;
    cout << p2.use_count() << endl;

    // Relinquishes ownership of p1 on the object
    //and pointer becomes NULL
    p1.reset();
    cout << p1.get() << endl;
    cout << p2.use_count() << endl;
    cout << p2.get() << endl;

    return 0;
}

Output:

0x1c41c20
A::show()
A::show()
0x1c41c20
0x1c41c20
2
2
0          // NULL
1
0x1c41c20


何时使用shared_ptr?


如果要共享资源的所有权,请使用shared_ptr。 很多shared_ptr可以指向单个资源。 shared_ptr维护这个引用计数,当所有shared_ptr指向资源超出范围时,资源被破坏。

weak_ptr

将weak_ptr创建为shared_ptr的副本。 它提供对一个或多个shared_ptr实例拥有的对象的访问权限,但不参与引用计数。 weak_ptr的存在或破坏对shared_ptr或其他副本没有影响。 在某些情况下需要中断shared_ptr实例之间的循环引用。

循环依赖(shared_ptr的问题):让我们考虑一个场景,我们有两个类A和B,它们都有指向其他类的指针。 所以,它总是像A指向B和B指向A.因此,use_count永远不会达到零,并且永远不会被删除。
这是我们使用弱指针(weak_ptr)的原因,因为它们不是引用计数。 所以,weak_ptr被声明的类没有很强的保持,即所有权不被共享,但是他们可以访问这些对象。

所以,在shared_ptr的情况下,由于循环依赖关系use_count从不达到零,这是阻止使用weak_ptr的,通过将A_ptr声明为weak_ptr来消除这个问题,因此A类不拥有它,只能访问它,我们还需要检查 对象的有效性可能超出范围。 一般来说,这是一个设计问题。

什么时候使用weak_ptr?


当你想要从多个地方引用你的对象 - 对于那些可以忽略和释放它们的引用(所以当你尝试取消引用时,它们只会注意到对象已经不见了)。

本篇博客主要是给读者对智能指针的使用做一个总结。。。。。。。。






auto_ptr, unique_ptr, shared_ptr and weak_ptr智能指针讲解的更多相关文章

  1. stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结

    stl中auto_ptr,unique_ptr,shared_ptr,weak_ptr四种智能指针使用总结 1. auto_ptrauto_ptr主要是用来解决资源自动释放的问题,比如如下代码:voi ...

  2. C++11 weak_ptr智能指针

    和 shared_ptr.unique_ptr 类型指针一样,weak_ptr 智能指针也是以模板类的方式实现的.weak_ptr<T>( T 为指针所指数据的类型)定义在<memo ...

  3. C++智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr

    手写代码是理解C++的最好办法,以几个例子说明C++四个智能指针的用法,转载请注明出处. 一.auto_ptr auto_ptr这是C++98标准下的智能指针,现在常常已经被C++标准的其他智能指针取 ...

  4. 聊聊智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr

    本文为转载:https://www.cnblogs.com/zeppelin5/p/10083597.html,对作者有些地方做了修正. 手写代码是理解C++的最好办法,以几个例子说明C++四个智能指 ...

  5. 第21课 shared_ptr共享型智能指针

    一. shared_ptr的基本用法 (一)与unique_ptr的比较 比较 shared_ptr unique_ptr 备注 初始化 ①shared_ptr<T> sp; sp.res ...

  6. auto_ptr,unique_ptr,shared_ptr,weak_ptr

    http://mojijs.com/2016/08/218129/index.html http://www.cnblogs.com/lanxuezaipiao/p/4132096.html

  7. 33.unique_ptr独享内存智能指针

    #include <iostream> #include <memory> #include <string> #include <vector> us ...

  8. auto_ptr与shared_ptr ZZ

    http://blog.csdn.net/rogeryi/article/details/1442700 Part(1) 这篇文章试图说明如何使用auto_ptr和shared_ptr,从而使得动态分 ...

  9. c++智能指针(unique_ptr 、shared_ptr、weak_ptr、auto_ptr)

    一.前序 什么是智能指针? ——是一个类,用来存储指针(指向动态分配对象也就是堆中对象的的指针). c++的内存管理是让很多人头疼的事,当我们写一个new语句时,一般就会立即把delete语句直接也写 ...

随机推荐

  1. python16_day14【jQuery】

    一.作用域 1.作用域例一 <script> var str = "global"; //AO1 AO1.str function t(age){ console.lo ...

  2. python 2 和python 3的 区别

    用户交互 input  ps:python2:raw_input python3:input 在 python2里 print不需要加括号也可以打印 子python3里 print 必须加括号才能打印

  3. JAVA接口中不可以有静态方法吗

    1. 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错),所以不能含有静态代码块以及静态方法(用 ...

  4. Microservice 概念

    一天我司招财猫姐(HR 大人)问我,你给我解释一下 Microservice 是什么吧.故成此文.一切都是从一个创业公司开始的. 故事 最近的创业潮非常火爆,我禁不住诱惑也掺和了进去,创建了一家公司. ...

  5. Qios RibbonForm QRibbonCaption添加qRibbonApplicationButton无法最大化问题

    winform 用了Qios DevSuite系列的控件. RibbonForm中QRibbonCaption添加qRibbonApplicationButton之后无法最大化. 修改qRibbonA ...

  6. 【学习ffmpeg】打开视频文件,帧分析,并bmp保存关键帧

    http://www.tuicool.com/articles/jiUzua   http://blog.csdn.net/code_future/article/details/8646717 主题 ...

  7. less预编译语言使用总结

    以前就使用过less和sass,其实很简单,就是很长时间不用,忘记语法了,现在来总结一片使用技巧 一.注释 less的注释不会被编译到css文件中,所以提倡多使用less中的注释:/**/ 二.变量 ...

  8. shell自动化一键部署脚本,秒级一键回滚脚本

    #!/bin/bash # Node List PRE_LIST="192.168.222.163" # 预生产环境节点 GROUP1_LIST= ROLLBACK_LIST=&q ...

  9. MySQL-checkpoint技术

    几个知识点: 缓冲池:缓存磁盘数据,通过内存速度弥补CPU速度和磁盘速度的鸿沟. 脏页:LRU列表中被修改的页,和磁盘上的数据不一致 刷新频率:每次有脏页就刷新,开销很大.需要一种刷新机制 数据丢失: ...

  10. Git服务器的Gitosis安装配置及gitignore的使用方法

    Git服务器Gitosis安装设置 1.安装 openssh服务器 sudo apt-get install openssh-server openssh-client 2.创建个人公钥和私钥 在默认 ...