share_ptr的正确使用方法

游戏用户管理的C++多线程实现
本文介绍了一种使用C++11的std::shared_ptr和std::enable_shared_from_this进行游戏用户在线状态管理的方法。通过创建玩家类并实现玩家登录和登出的功能,展示了如何使用智能指针在多线程环境中安全地管理资源。

实在是看不惯度娘出来的share ptr的例子,没有实用性,而且还不清晰,举一个场景如下:

假设游戏玩家登陆时要登记到一个管理用的vector中,登出时删除,程序如下:

注意对象时在函数结束时才被释放的。

 

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>

#include <iostream>
#include <vector>
#include <string>

using namespace std;
class player;

typedef boost::shared_ptr<player> pplayer;
typedef vector<pplayer> player_container;

player_container PC;

class player:public boost::enable_shared_from_this<player>,boost::noncopyable
{
public:
 player(string name_)
 {
  name = name_;
  cout << "new>>>>" << name <<":"<<__FUNCTION__ << ":" << __LINE__ << endl;
 }

 ~player()
 {
  cout << "delete>>>>" << name <<":"<< __FUNCTION__ << ":" << __LINE__ << endl;
 }

 static pplayer CreatePlayer(string name)
 {
  pplayer pp(new player(name));
  return pp;
 }

 void Login()
 {
  cout << name  <<" login:" << endl;
  PC.push_back(shared_from_this());
 }

 void Logout()
 {
  cout << name << " logout " << endl;
  pplayer me = shared_from_this();
  player_container::iterator it = std::find(PC.begin(), PC.end(), me);
  PC.erase(it);
 }

 string GetName() const
 {
  return name;
 }
private:
 string name;
 int account;
 int charid; 
};


void player_manager()
{
 pplayer pp1 = player::CreatePlayer("zhangSan");
 pp1->Login();
 pp1->Logout();

 pplayer pp1_new = pp1;
 pplayer pp1_new2 = pp1;

 cout << "pp1 share count: " << pp1->shared_from_this().use_count() << endl;
 pplayer pp2 = player::CreatePlayer("LiSi");
 pp2->Login();
 pp2->Logout();

 pplayer pp3 = player::CreatePlayer("Wang2Mazi");
 pp3->Login();
 pp3->Logout();
}

int main(int argc,char**agrv)
{
    player_manager();
 system("pause");
 return 0;
}

 

 



<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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值