linux C++共享指针(std::shared_ptr、std::make_shared)共享对象,reset()重置共享指针,use_count()查看引用计数,与unique_ptr区别

462 篇文章 29 订阅


共享指针是一种智能指针,它提供了与 std::unique_ptr 相似的语法,但是它允许多个指针共享同一对象的所有权。
当不再需要该对象时,共享指针会自动计数,并在没有任何指针指向该对象时释放它。

示例

#include <memory>
#include <string>
#include <iostream>

int main()
{
    // 创建一个指向字符串的 shared_ptr
    std::shared_ptr<std::string> event = std::make_shared<std::string>("This is an event.");    //This is an event.
    std::cout << *event << std::endl;

    // 查看共享对象引用计数
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 1

    // 多个 shared_ptr 可以指向同一个对象
    std::shared_ptr<std::string> event2 = event;
    std::cout << *event2 << std::endl;                                                          //This is an event.

    // 查看共享对象引用计数
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 2
    std::cout << "event2.use_count() = " << event2.use_count() << std::endl;                    //event2.use_count() = 2


    // 对象只有当所有 shared_ptr 对它的引用都断开后,才会被销毁
    event.reset();
    // 查看共享对象引用计数
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 0     //如果共享指针已被销毁,查看其引用计数,不会报错,值为0,有点奇怪(下同)
    std::cout << "event2.use_count() = " << event2.use_count() << std::endl;                    //event2.use_count() = 1
    event2.reset();
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 0
    std::cout << "event2.use_count() = " << event2.use_count() << std::endl;                    //event2.use_count() = 0

    return 0;
}

上面代码中,我们通过 std::make_shared<std::string>("This is an event.") 创建了一个指向字符串的 shared_ptr。然后我们复制这个指针到了 event2,现在两个指针都指向了同一个字符串。当我们在最后调用 event.reset()event2.reset() 时,因为两个指针都不再引用这个字符串,所以这个字符串就会被销毁。

注意:如果共享指针已被reset(),查看其引用计数,不会报错,值为0,为何?因为调用reset()只是将共享指针指向置为nullptr,reset(std::shared_ptr.get())还可以将共享指针指向另一个共享指针所管理的内存

当一个 std::shared_ptr 对象调用 reset() 函数后,它所管理的对象的引用计数会减1,如果这个 std::shared_ptr 对象是最后一个指向该对象的 std::shared_ptr 对象,则这个对象所管理的资源会被销毁,引用计数会变为0。

当调用 reset() 函数后,这个 std::shared_ptr 对象本身会变为空(即不指向任何对象),而且其 use_count() 函数的返回值会变成0。因此,如果之后再调用这个被 reset() 后的 std::shared_ptr 对象的 use_count() 函数,其返回值仍然为0,因为这个 std::shared_ptr 对象已经不再指向任何对象了。

需要注意的是,在调用 reset() 函数后,共享指针对象会将自己的指针置为空,即不再指向任何对象。因此,如果之后调用这个共享指针对象的成员函数,如 use_count(),就会导致未定义行为。所以,为了避免这种情况发生,我们应该在调用 reset() 后避免对这个共享指针对象进行任何操作。

测试代码
#include <memory>
#include <string>
#include <iostream>
#include <chrono>
#include <thread>

int main()
{
    // 创建一个指向字符串的 shared_ptr
    std::shared_ptr<std::string> event = std::make_shared<std::string>("This is an event.");    //This is an event.
    std::cout << *event << std::endl;

    // 打印共享对象指向的资源地址
    std::cout << "event.get() = " << event.get() << std::endl;                                  //event.get() = 0x55f8cf40eec0

    // 查看共享对象引用计数
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 1

    // 对象只有当所有 shared_ptr 对它的引用都断开后,才会被销毁
    event.reset();  //将共享指针指向置为nullptr

    // 打印共享对象指向的资源地址
    std::cout << "event.get() = " << event.get() << std::endl;                                  //event.get() = 0   //指向资源地址为空指针nullptr

    // 查看共享对象引用计数
    std::cout << "event.use_count() = " << event.use_count() << std::endl;                      //event.use_count() = 0
    return 0;
}

编译运行结果:
在这里插入图片描述

如何确认引用计数为0后,被共享指针管理的共享对象是否已销毁?

可以在共享对象的析构函数中设置标识,然后在确定引用计数为0后,检查这个标识以确定共享对象是否已销毁。

#include <iostream>
#include <memory>

class A
{
public:
    A()
    {
        std::cout << "A Constructed" << std::endl;
    }
    ~A()
    {
        std::cout << "A Destructed" << std::endl;
    }
};

int main()
{
    std::shared_ptr<A> pA(new A);
    std::cout << "A's Reference Count: " << pA.use_count() << std::endl;
    std::shared_ptr<A> pB = pA;
    std::cout << "A's Reference Count: " << pA.use_count() << std::endl;
    std::cout << "B's Reference Count: " << pB.use_count() << std::endl;
    pA.reset();
    std::cout << "A's Reference Count: " << pA.use_count() << std::endl;
    std::cout << "B's Reference Count: " << pB.use_count() << std::endl;
    pB.reset();
    std::cout << "A's Reference Count: " << pA.use_count() << std::endl;
    std::cout << "B's Reference Count: " << pB.use_count() << std::endl;

    return 0;
}

编译运行:

g++ test.cpp && ./a.out

结果:
在这里插入图片描述

std::shared_ptr和std::unique_ptr有什么区别?

std::shared_ptr和std::unique_ptr是C++11中提供的智能指针类模板,它们都提供了一种安全且方便的方式来管理动态分配的内存。

主要区别:

  • 所有权的管理方式不同。
    std::unique_ptr是一种独占式智能指针,它对于所管理的对象具有唯一的所有权。这意味着一个std::unique_ptr指针不能与另一个指针共享所有权,也不能将其复制到另一个std::unique_ptr对象中。
    std::shared_ptr是一种共享式智能指针,它允许多个指针共享对所管理的对象的所有权。当没有任何std::shared_ptr指针指向对象时,对象才会被自动销毁。

  • 内存管理方式不同。
    std::unique_ptr使用基于移动语义的所有权转移方式来管理内存。这意味着当一个std::unique_ptr对象被赋值或传递给另一个对象时,它所管理的对象的所有权将被转移到新的std::unique_ptr对象。
    std::shared_ptr使用引用计数的内存管理方式来管理内存。每当一个新的std::shared_ptr指针指向一个对象时,该对象的引用计数会增加。当一个std::shared_ptr指针不再指向对象时,该对象的引用计数会减少。只有当对象的引用计数变为零时,该对象才会被自动销毁。

  • 性能差异。
    由于std::shared_ptr需要在堆上维护一个引用计数,因此它的构造和赋值操作比std::unique_ptr慢,并且它也可能涉及额外的线程同步开销。但是,std::shared_ptr可以方便地实现多个指针之间的共享所有权,因此在需要共享所有权的情况下,它可能是更好的选择。

总之,std::unique_ptr适用于独占式的所有权管理,对于无需共享所有权的情况,它通常是更好的选择。std::shared_ptr适用于需要共享所有权的情况,但由于额外的引用计数和线程同步开销,它可能会导致性能问题。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dontla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值