zoukankan      html  css  js  c++  java
  • C++11 智能指针

    上一篇线程池里,有一个返回std::shared_ptr<T>对象,他其实是c++里面的智能指针

    shared_ptr共享被管理对象,同一时刻可以有多个shared_ptr拥有对象的所有权,当最后一个shared_ptr对象销毁时,被管理对象自动销毁 

    std::shared_ptr大概总结有以下几点:

    (1) 智能指针主要的用途就是方便资源的管理,自动释放没有指针引用的资源

    (2) 使用引用计数来标识是否有多余指针指向该资源。(注意,shart_ptr本身指针会占1个引用)

    (3) 在赋值操作中, 原来资源的引用计数会减一,新指向的资源引用计数会加一。

         std::shared_ptr<Test> p1(new Test);

         std::shared_ptr<Test> p2(new Test);

         p1 = p2;

    (4) 引用计数加一/减一操作是原子性的,所以线程安全的。

    (5) make_shared要优于使用new,make_shared可以一次将需要内存分配好

    std::shared_ptr<Test> p = std::make_shared<Test>();
    std::shared_ptr<Test> p(new Test);

    (6) std::shared_ptr的大小是原始指针的两倍,因为它的内部有一个原始指针指向资源,同时有个指针指向引用计数。

    (7) 引用计数是分配在动态分配的,std::shared_ptr支持拷贝,新的指针获可以获取前引用计数个数。

    以下是cppreference的代码例子,其实也蛮清楚的

    #include <iostream>
    #include <memory>
    #include <thread>
    #include <chrono>
    #include <mutex>
    
    struct Base
    {
        Base() { std::cout << "  Base::Base()
    "; }
        // 注意:此处非虚析构函数 OK
        ~Base() { std::cout << "  Base::~Base()
    "; }
    };
    
    struct Derived : public Base
    {
        Derived() { std::cout << "  Derived::Derived()
    "; }
        ~Derived() { std::cout << "  Derived::~Derived()
    "; }
    };
    
    void thr(std::shared_ptr<Base> p)
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::shared_ptr<Base> lp = p; // 线程安全,虽然自增共享的 use_count
        {
            static std::mutex io_mutex;
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << "local pointer in a thread:
    "
                      << "  lp.get() = " << lp.get()
                      << ", lp.use_count() = " << lp.use_count() << '
    ';
        }
    }
    
    int main()
    {
        std::shared_ptr<Base> p = std::make_shared<Derived>();
    
        std::cout << "Created a shared Derived (as a pointer to Base)
    "
                  << "  p.get() = " << p.get()
                  << ", p.use_count() = " << p.use_count() << '
    ';
        std::thread t1(thr, p), t2(thr, p), t3(thr, p);
        p.reset(); // 从 main 释放所有权
        std::cout << "Shared ownership between 3 threads and released
    "
                  << "ownership from main:
    "
                  << "  p.get() = " << p.get()
                  << ", p.use_count() = " << p.use_count() << '
    ';
        t1.join();
        t2.join();
        t3.join();
        std::cout << "All threads completed, the last one deleted Derived
    ";
    }
    View Code

    但是有没有可能double free呢

    double Free其实就是同一个指针free两次。虽然一般把它叫做double free。其实只要是free一个指向堆内存的指针都有可能产生可以利用的漏洞。

    double free的原理其实和堆溢出的原理差不多,都是通过unlink这个双向链表删除的宏来利用的。只是double free需要由自己来伪造整个chunk并且欺骗操作系统

    简单来说,shared_ptr实现包含了两部分,

    • 一个指向堆上创建的对象的裸指针,raw_ptr

    • 一个指向内部隐藏的、共享的管理对象。share_count_object

    第一部分没什么好说的,第二部分是需要关注的重点:

    • use_count,当前这个堆上对象被多少对象引用了,简单来说就是引用计数。

    • weak_count,这个管理对象被多少个智能指针共享了,简单来说就是管理对象的引用计数。

    不同指针创建的对同一个堆上对象的智能管理,并不共享管理对象,因此存在double free的可能性

  • 相关阅读:
    一文掌握Docker Compose
    Flannel配置详解
    Helm二:安装
    Helm一:简介
    ubuntu内核及系统升级
    Ogre 编辑器一(MyGUI+Ogre整合与主界面)
    MyGUI 解析
    Ogre 监听类与渲染流程
    OpenGL 阴影之Shadow Mapping和Shadow Volumes
    Ogre RTSS组件解析
  • 原文地址:https://www.cnblogs.com/BobHuang/p/11259543.html
Copyright © 2011-2022 走看看