• sharedPtr


    shared_ptr

    在这里插入图片描述

    1.以何种方式传递

    通过下列方式将 shared_ptr 传递给其他函数:

    按值传递 shared_ptr。 这将调用复制构造函数,增加引用计数,并使被调用方成为所有者。 此操作的开销很小,但此操作的开销可能很大,具体取决于要传递多少 shared_ptr 对象。 当调用方和被调用方之间的(隐式或显式)代码协定要求被调用方是所有者时,请使用此选项。

    按引用或常量引用传递 shared_ptr。 在这种情况下,引用计数不会增加,并且只要调用方不超出范围,被调用方就可以访问指针。 或者,被调用方可以决定基于引用创建一个 shared_ptr,并成为一个共享所有者。 当调用方并不知道被调用方,或当您由于性能原因必须传递一个 shared_ptr 且希望避免复制操作时,请使用此选项。

    传递基础指针或对基础对象的引用。 这使被调用方能够使用对象,但不会使其能够共享所有权或延长生存期。 如果被调用方通过原始指针创建一个 shared_ptr,则新的 shared_ptr 独立于原始的,并且不会控制基础资源。 当调用方和被调用方之间的协定明确指定调用方保留 shared_ptr 生存期的所有权时,请使用此选项。

    在确定如何传递 shared_ptr 时,确定被调用方是否必须共享基础资源的所有权。 “所有者”是只要它需要就可以使基础资源一直有效的对象或函数。 如果调用方必须保证被调用方可以将指针的生命延长到其(函数)生存期以外,则请使用第一个选项。 如果您不关心被调用方是否延长生存期,则按引用传递并让被调用方复制或不复制它。

    如果必须为帮助器函数提供对基础指针的访问权限,并且你知道帮助器函数将使用该指针并且将在调用函数返回前返回,则该函数不必共享基础指针的所有权。 它只需在调用方的 shared_ptr 的生存期内访问指针即可。 在这种情况下,按引用传递 shared_ptr 或传递原始指针或对基础对象的引用是安全的。 通过此方式传递将提供一个小的性能好处,并且还有助于您表达编程意图。

    有时,例如,在一个 std::vector 中,您可能必须将每个 shared_ptr 传递给 lambda 表达式主体或命名函数对象。 如果 lambda 或函数没有存储指针,则将按引用传递 shared_ptr 以避免调用每个元素的复制构造函数

    2. 裸指针

    shared_ptr sp = new int(100);//不能用裸指针初始化sp
    share_ptr sp3(new int(100));//合法
    
    int *x(new int(100));
    shared_ptr sp1(x);
    shared_ptr sp2(x);
    //x为裸指针,不合法,且sp1 sp2虽然都指向x所指向的内存,但是二者是独立的,当sp1释放时,x会变成空悬指针,sp2也很危险了
    
    shared_ptr sp1(new int(10));
    
    shared_ptr sp2(sp1.get());//get返回的是裸指针,error
    sp.reset(sp1.get());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3. 线程安全

    (shared_ptr)的引用计数本身是安全且无锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原子化。根据文档(http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm#ThreadSafety), shared_ptr 的线程安全级别和内建类型、标准库容器、std::string 一样,即:

    • 一个 shared_ptr 对象实体可被多个线程同时读取(文档例1);

    • 两个 shared_ptr 对象实体可以被两个线程同时写入(例2),“析构”算写操作;

    • 如果要从多个线程读写同一个 shared_ptr 对象,那么需要加锁(例3~5)。

    请注意,以上是 shared_ptr 对象本身的线程安全级别,不是它管理的对象的线程安全级别。

    后文(p.18)则介绍如何高效地加锁解锁。本文则具体分析一下为什么“因为 shared_ptr 有两个数据成员,读写操作不能原子化”使得多线程读写同一个 shared_ptr 对象需要加锁。这个在我看来显而易见的结论似乎也有人抱有疑问,那将导致灾难性的后果,值得我写这篇文章。本文以 boost::shared_ptr 为例,与 std::shared_ptr 可能略有区别。

    shared_ptr 的数据结构
    shared_ptr 是引用计数型(reference counting)智能指针,几乎所有的实现都采用在堆(heap)上放个计数值(count)的办法(除此之外理论上还有用循环链表的办法,不过没有实例)。具体来说,shared_ptr 包含两个成员,一个是指向 Foo 的指针 ptr,另一个是 ref_count 指针(其类型不一定是原始指针,有可能是 class 类型,但不影响这里的讨论),指向堆上的 ref_count 对象。ref_count 对象有多个成员,具体的数据结构如图 1 所示,其中 deleter 和 allocator 是可选的。

    unordered容器时,退化成链表

    shared_ptr 作为 unordered_map 的 key
    如果把 boost::shared_ptr 放到 unordered_set 中,或者用于 unordered_map 的 key,那么要小心 hash table 退化为链表。http://stackoverflow.com/questions/6404765/c-shared-ptr-as-unordered-sets-key/12122314#12122314

    直到 Boost 1.47.0 发布之前,unordered_set 虽然可以编译通过,但是其 hash_value 是 shared_ptr 隐式转换为 bool 的结果。也就是说,如果不自定义hash函数,那么 unordered_{set/map} 会退化为链表。https://svn.boost.org/trac/boost/ticket/5216

    Boost 1.51 在 boost/functional/hash/extensions.hpp 中增加了有关重载,现在只要包含这个头文件就能安全高效地使用 unordered_setstd::shared_ptr 了。

    refhttps://blog.csdn.net/solstice/article/details/8547547

    4 管理socket FILE

    将打开的文件句柄交给shared_ptr管理,如果发生任何不当行为,shared_ptr会帮助我们自动释放资源,程序员也不用自己显式写出fclose。
    如果文件不存在,那么shared_ptr管理的是空指针,这样会在fclose发生异常,为了避免,先打开后判断是否为空哈

    shared_ptr fp(fopen("/test.txt","r"),fclose);
    
    • 1

    一个自定义类管理套接字资源,自定义一个合适的资源释放函数,更加高效!!

    Socket* openSocket()
    {
    	//do something
    }
    
    void closeSocket()
    {
    	//do something
    }
    
    auto s= openSocket();
    if (s != nullptr)
    {
        shared_ptr p(s, closeSocket);
    }
    else
    {
        return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    5. 性能

    1. share_ptr的size是裸指针的两倍:指向到该资源的裸指针,指向到该资源的引用计数的裸指针
    2. 引用计数的内存必须动态分配
    3. 引用计数的递增和递减必须是原子操作
    
    • 1
    • 2
    • 3

    6. 数组与容器

    1. share_ptr的size是裸指针的两倍:指向到该资源的裸指针,指向到该资源的引用计数的裸指针
    2. 引用计数的内存必须动态分配
    3. 引用计数的递增和递减必须是原子操作
    
    • 1
    • 2
    • 3

    6. 数组与容器

    ​ 没有所谓的share_ptr,以array vector string替代,但是unique_ptr有

  • 相关阅读:
    SpringMVC入门到实战------2、SpringMVC创建实例Hello SpringMVC(maven+tomcat)
    阻止IP地址追踪的意义和编程实现
    FineBI 新增字段后 更新缓慢问题
    购买问界M7大五座(自动驾驶走进我们的生活一)
    LVS-群集架构介绍(linux 虚拟服务)
    致敬经典 睛彩再现——AVS产业联盟和中国移动咪咕公司携手推动AVS3视频、音频标准
    关于SELECT...FOR UPDATE到底锁表还是锁行
    掏空了各大搜索引擎,整理了154道Java面试题!
    生成随机数的若干种方法
    【MySQL】库操作和表操作
  • 原文地址:https://blog.csdn.net/Kiris_king/article/details/128094957