[C++11]_[初级]_[shared_ptr的使用场景]

本文介绍了C++11中shared_ptr的使用场景,特别是在多线程环境中解决对象共享和线程安全问题的优势。通过举例展示了shared_ptr如何创建、封装到vector中、自定义释放函数以及在多线程访问中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

  1. C++11之前,使用auto_ptr只能适用于 new 出来的对象,为此我还专门创建了一些工具类来释放对象.使用智能指针的方式释放malloc出来的堆空间,C++11出现后可以使用shared_ptr来管理C指针了.

  2. 多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用,在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃,所以为了省时间一般都是任由这个内存泄漏发生.当然也可以经过复杂的设计,由一个监控线程来统一删除,但这样会增加代码量和复杂度.这下好了,shared_ptr 可以方便的解决问题,因为它是引用计数和线程安全的.

参考

std::shared_ptr

说明

shared_ptr的所有的方法(包括复制构造函数 和 赋值重载)都能被多线程中的不同shared_ptr实例(拥有相同的对象)安全的调用而不需要额外的同步操作.

使用

创建方式

<think>嗯,用户让我介绍一下shared_ptr,我需要用中文详细解释清楚。首先,我应该从基础概念入手,解释shared_ptr是什么,属于智能指针的一种,然后说明它的作用和管理内存的方式。可能需要对比其他类型的智能指针,比如unique_ptr和weak_ptr,来突出shared_ptr的特点。 接下来要讲清楚shared_ptr的核心机制,也就是引用计数。这里要说明引用计数是如何工作的,当有新的shared_ptr指向同一个对象时,计数增加,反之则减少,当计数归零时自动释放内存。这部分可能需要举例说明,比如创建多个shared_ptr实例时的情况。 然后,用户可能需要了解如何正确使用shared_ptr。这时候应该提到初始化方法,比如使用make_shared而不是直接new,这样可以提高效率和安全性。还要强调循环引用的问题,以及如何用weak_ptr来避免,这是常见的问题点,必须详细说明。 另外,使用场景也是重点。需要说明在哪些情况下适合使用shared_ptr,比如多个对象共享同一资源时。同时,也要提到性能考虑,因为引用计数会有一定的开销,不适合在性能敏感的场景滥用。 可能用户对线程安全也有疑问,这里需要解释shared_ptr本身的线程安全性,指出引用计数的原子操作是线程安全的,但对象访问需要额外同步。这部分需要准确,避免误导。 最后,常见错误和注意事项也需要涵盖,比如不要混合使用原始指针shared_ptr,避免内存泄漏或重复释放。还可以举一个简单的代码例子,展示基本用法,并指出循环引用的例子,以及如何用weak_ptr解决。 需要确保整个回答结构清晰,分点说明,语言通俗易懂,避免过于技术化的术语,同时覆盖用户可能关心的各个方面。检查是否有遗漏的部分,比如构造函数、自定义删除器的用法,是否需要简要提及?可能对于初级用户来说,先掌握基本用法更重要,高级用法可以稍后学习,所以暂时不深入。 还要注意用户可能对引用计数的实现细节感兴趣,但可能不需要太底层的解释,所以保持在高层次的概念层面即可。确保每个部分之间有逻辑衔接,让读者能够逐步理解shared_ptr的工作原理和使用方法。 总结下来,回答的结构应该是:定义和作用、核心机制(引用计数)、基本用法、循环引用问题、使用场景、线程安全、注意事项,最后代码示例。这样分步骤介绍,帮助用户建立全面的理解。</think>以下是对`shared_ptr`的逐步介绍: --- ### 一、定义与作用 `shared_ptr`是C++标准库提供的**智能指针**,用于管理动态分配的内存。它通过**引用计数**机制实现多个指针共享同一对象,确保当最后一个`shared_ptr`离开作用域时,对象被自动释放。 --- ### 二、核心机制:引用计数 1. **引用计数原理** 每个`shared_ptr`内部维护一个计数器: - 当新`shared_ptr`指向同一对象时,计数**+1** - 当`shared_ptr`被销毁(如离开作用域)时,计数**-1** - 当计数归零时,自动调用`delete`释放对象 2. **示例说明** ```cpp std::shared_ptr<int> p1(new int(42)); // 引用计数=1 { std::shared_ptr<int> p2 = p1; // 引用计数=2 } // p2销毁,引用计数=1 ``` `p1`销毁时,引用计数归零,内存自动释放。 --- ### 三、基本用法 1. **初始化方式** - 推荐使用`std::make_shared`(更高效、安全): ```cpp auto p = std::make_shared<int>(42); ``` - 直接初始化(需避免混用原始指针): ```cpp std::shared_ptr<int> p(new int(42)); ``` 2. **访问对象** ```cpp std::cout << *p << std::endl; // 解引用 p->method(); // 访问成员 ``` --- ### 四、循环引用问题 1. **问题描述** 当两个`shared_ptr`互相指向对方时,引用计数无法归零,导致内存泄漏: ```cpp class A { std::shared_ptr<B> b_ptr; }; class B { std::shared_ptr<A> a_ptr; }; auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); a->b_ptr = b; // A引用B,计数=2 b->a_ptr = a; // B引用A,计数=2 ``` 2. **解决方案** 使用`weak_ptr`打破循环: ```cpp class B { std::weak_ptr<A> a_ptr; // 改为weak_ptr }; ``` --- ### 五、使用场景 - 多个对象需要共享同一资源(如缓存、配置文件) - 对象所有权不明确,需动态管理生命周期 --- ### 六、线程安全性 - **引用计数操作是原子的**,线程安全 - **对象访问需额外同步**(如互斥锁) --- ### 七、注意事项 1. 避免混用原始指针与`shared_ptr` ```cpp int* raw_ptr = new int(10); std::shared_ptr<int> p1(raw_ptr); std::shared_ptr<int> p2(raw_ptr); // 错误!重复释放 ``` 2. 不要返回`shared_ptr`管理的原始指针 3. 优先使用`make_shared`而非`new` --- ### 八、代码示例 ```cpp #include <memory> #include <iostream> class Resource { public: Resource() { std::cout << "Resource created\n"; } ~Resource() { std::cout << "Resource destroyed\n"; } }; int main() { auto ptr1 = std::make_shared<Resource>(); // 计数=1 { auto ptr2 = ptr1; // 计数=2 } // 计数=1 return 0; // 计数=0,资源释放 } ``` --- ### 总结 `shared_ptr`通过引用计数简化内存管理,但需注意循环引用和原始指针混用问题。结合`weak_ptr`和`make_shared`可提高代码安全性与效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

白行微

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

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

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

打赏作者

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

抵扣说明:

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

余额充值