c++中的四种智能指针

写惯了python,golang再来写c++总觉得头大,很大一个原因就是他没有一个GC机制。

不过c++中提供了智能指针,也不是不能用,李姐万岁!

auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被11弃用。

1.auto_ptr

这个指针采用了所有权的方式,

#include<memory>
#include <iostream>
using namespace std;
int main() {
    auto_ptr<string> p_s1(new string("this is  a string"));
    cout << *p_s1.get() << endl;
    auto_ptr<string> p_s2 = p_s1;
    cout << *p_s2.get() << endl;
    //cout << *p_s1.get() << endl;报错,此时s1已经没有所指向的内存的所有权
}

auto_ptr的缺点是:存在潜在的内存崩溃问题!

2.unique_ptr

unique_ptr同样是独占的,但unique_ptr还有更聪明的地方:当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做。

实在想赋值的话,可以用std::move()实现。

#include<memory>
#include <iostream>
using namespace std;
int main() {
    unique_ptr<string> p_s1(new string("this is  a string"));//临时右值是可以用来赋值的
    cout << *p_s1.get() << endl;
    //unique_ptr<string> p_s2 =p_s1;无法直接赋值
    unique_ptr<string> p_s2 = std::move(p_s1);
    cout << *p_s2.get() << endl;
}

3.shared_ptr

shared_ptr实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。从名字share就可以看出了资源可以被多个指针共享,它使用计数机制(和python的垃圾回收机制也很像)来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。除了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造,也可以通过make_shared函数或者通过构造函数传入普通指针。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。

shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使用引用计数的机制上提供了可以共享所有权的智能指针,其可以检测到所管理的对象是否已经被释放,从而避免非法访问。

4. weak_ptr

weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。

class B;
class A
{
public:
    shared_ptr<B> pb_;
    ~A()
    {
        cout << "A delete"<<pb_.use_count()<<endl;
    }
};
class B
{
public:
    shared_ptr<A> pa_;
    ~B()
    {
        cout << "B delete"<<pa_.use_count()<<endl;
    }
};
void fun()
{
    shared_ptr<B> pb(new B());
    shared_ptr<A> pa(new A());
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout << pb.use_count() << endl;
    cout << pa.use_count() << endl;
}
int main()
{
    fun();
    return 0;
}

可以看到fun函数中pa ,pb之间互相引用,两个资源的引用计数为2,当要跳出函数时,智能指针pa,pb析构时两个资源引用计数会减一,但是两者引用计数还是为1,导致跳出函数时资源没有被释放(A B的析构函数没有被调用),如果把其中一个改为weak_ptr就可以了,我们把类A里面的shared_ptr pb_; 改为weak_ptr pb_; 运行结果如下,

1
2
B delete1
A delete0

这样的话,资源B的引用开始就只有1,当pb析构时,B的计数变为0,B得到释放,B释放的同时也会使A的计数减一,同时pa析构时使A的计数减一,那么A的计数为0,A得到释放。

注意的是我们不能通过weak_ptr直接访问对象的方法,比如B对象中有一个方法print(),我们不能这样访问,pa->pb_->print(); 英文pb_是一个weak_ptr,应该先把它转化为shared_ptr,如:shared_ptr p = pa->pb_.lock(); p->print();

改后如下

class B;
class A
{
public:
    weak_ptr<B> pb_;
    ~A()
    {
        cout << "A delete"<<pb_.use_count()<<endl;
    }

};
class B
{
public:
    shared_ptr<A> pa_;
    ~B()
    {
        cout << "B delete"<<pa_.use_count()<<endl;
    }
    void func() {
        cout << "this is print" << endl;
    }
};
void fun()
{

    shared_ptr<A> pa(new A());
    shared_ptr<B> pb(new B());
    pb->pa_ = pa;
    pa->pb_ = pb;
    cout << pb.use_count() << endl;
    cout << pa.use_count() << endl;
    (*(*pa).pb_.lock()).func();
}
int main()
{
    fun();
    return 0;
}

输出如下

1
2
this is print
B delete2
A delete

c++中的四种智能指针的更多相关文章

  1. 转载:STL四种智能指针

    转载至:https://blog.csdn.net/K346K346/article/details/81478223 STL一共给我们提供了四种智能指针: auto_ptr.unique_ptr.s ...

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

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

  3. c++ 中的8种智能指针[转]

    一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 ...

  4. C++中的四个智能指针

    只能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象.智能指针定义在memory头文件中. 1. auto_ptr(C++11已经舍弃) 由new expression获得的对象,在au ...

  5. 聊聊 C++ 中的几种智能指针 (下)

    一:背景 上一篇我们聊到了C++ 的 auto_ptr ,有朋友说已经在 C++ 17 中被弃用了,感谢朋友提醒,今天我们来聊一下 C++ 11 中引入的几个智能指针. unique_ptr shar ...

  6. 聊聊 C++ 中的几种智能指针 (上)

    一:背景 我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露 ...

  7. C++中的四种转型操作符

    在具体介绍C++中的四种转型操作符之前,我们先来说说旧式转型的缺点: ①它差点儿同意将不论什么类型转换为不论什么其它类型,这是十分拙劣的.假设每次转型都可以更精确地指明意图,则更好. ②旧式转型难以辨 ...

  8. 对称加密和分组加密中的四种模式(ECB、CBC、CFB、OFB)

    一. AES对称加密: AES加密 分组 二. 分组密码的填充 分组密码的填充 e.g.: PKCS#5填充方式 三. 流密码:   四. 分组密码加密中的四种模式: 3.1 ECB模式 优点: 1. ...

  9. JAVA基础学习之throws和throw的区别、Java中的四种权限、多线程的使用等(2)

    1.throws和throw的区别 throws使用在函数外,是编译时的异常,throw使用在函数内,是运行时的异常 使用方法 public int method(int[] arr) throws ...

随机推荐

  1. [VIJOS2053][SDOI2019]世界地图:最小生成树+虚树

    分析 可以发现第一列和最后一列永远不会被删除,于是我们可以想到维护前后缀最小生成树,但是直接维护的话显然时间空间两爆炸.(通过上网找题解)可以发现我们关心的只是最左边和最右边两列,而不关心内部的连边情 ...

  2. java从ldap中导出数据到ldif文件中

    原创:http://www.cnblogs.com/dqcer/p/7814034.html 导入ldap.jar包,笔者已对下面两个文件测试并通过.若有疑问欢迎留言 LDAPExport.java ...

  3. 【python】小型神经网络的搭建

    import numpy as np def sigmoid(x): # Sigmoid activation function: f(x) = 1 / (1 + e^(-x)) return 1 / ...

  4. 第11组 Beta冲刺(2/5)

    第11组 Beta冲刺(2/5) 队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/11997386.html 作业博客 https://edu.cn ...

  5. Python学习笔记:第一次接触

    用的是windows的IDLE(python 3) 对象的认识:先创建一个list对象(用方括号) a = ['xieziyang','chenmanru'] a 对list中对象的引用 a[0] # ...

  6. pom文件中的dependencyManagement和dependencies的区别

    dependencies 子项目中,自动继承父项目中的相关依赖 dependencyManagement 只是声明依赖,并不实现引入,因此子项目中需要显示的声明需要用的依赖.如果不在子项目中声明依赖, ...

  7. windows环境安装nexus

    1.下载安装nexus安装包,我用的是nexus-2.14.13-01版本 2. 以管理员身份打开cmd命令窗口 3.进入到nexus bin目录下 输入命令 nexus install 4. 启动 ...

  8. RF Setup和Teardown的使用

    执行顺序 setup执行顺序是:project级别setup>suite级别setup>case级别setup 无返回值 Run Keywords | [KW1 | arg1 | arg2 ...

  9. java 中的多态

    多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,就是同一种事物表现出的多种形态. 下面利用代码进行简单概述: 实现多态必须要满足三个条件 1必须有继承 2必须重写 3必须父类引用子类对象 ...

  10. C++抽象类实践

    实践如下: #include <iostream> using namespace std; class Service { public: // 有一个虚函数即为抽象类 int id; ...