我的第一本C++书

游历C++世界的地图

C++小品:weak_ptr与传达室的花名册

原文来自

http://imcc.blogbus.com/logs/162618478.html

在C++11中,我们可以使用shared_ptr管理某个对象的所有权,负责对象的析构。然而在某些情况下,我们只是希望安全的访问某个对象,而不想拥有这个对象的所有权,对这个的析构负责(有点像电视剧中的那些不负责任的男人哦,只是玩玩而已,不会负责)。在这种情况下,我们可以使用表示弱引用的weak_ptr。

weak_ptr可以由一个shared_ptr构建,表示这个weak_ptr拥有这个shared_ptr所指向的对象的访问权,注意,这里仅仅是访问权,它不会改变智能指针的引用计数,自然也就不会去析构这个对象。利用weak_ptr,我们就可以安全地访问那些不具备所有权的对象。

一个现实中的例子就是学校的传达室,传达室拥有一本学生的名单,如果某个电话来了找某个学生,传达室会根据花名册去尝试访问这个学生,如果这个学生还在学校,就直接呼叫这个学生,如果已经离开了,这给这个学生留一个消息。在这里,花名册上的学生可能还在学校(对象还存在),也可能已经离开学校(对象已经析构),我们都需要对其进行访问,而weak_ptr就是用来访问这种不确定是否存在的对象的。

#include <iostream>
#include <map>
#include <algorithm>
#include <memory>
using namespace std;

// 学校的同学
class human
{
public:
human(string _n):name(_n)
{};
~human()
{
cout<<name<<" was destructed."<<endl;
}
void call() // 嘿,有个电话找你
{
cout<<name<<" was called."<<endl;
}
private:
string name;
};
// 传达室
class doorman
{
public:
doorman(map<string,shared_ptr<human>> humans)
{
// 根据学生对象构造花名册,注意其中保存的是有shared_ptr构造的weak_ptr
for_each(humans.begin(),humans.end(),
[&names](pair<string,shared_ptr<human>> h)
{
names[h.first] = weak_ptr<human>(h.second);
});
}
// 有个电话打到了传达室
void call(string name)
{
// 找找看,花名册中有没有这个学生
auto it = names.find(name);
// 如果有
if(it!=names.end())
{
auto man = (*it).second;
// 用lock()函数尝试获得weak_ptr所指向的shared_ptr,保存为p
if(auto p = man.lock())
p->call(); // 如果找到关联的shared_ptr,也就是这个对象还存在,也就是这个学生还在学校,呼叫之
else // 如果无法得到关联的shared_ptr,表示这个对象已经不存在了,学生离开了学校,只能给他留一个消息了
{
leavemsg(name);
}
}
else // 如果花名册中根本没有这个名字
{
cout<<name<<" is not in the school."<<endl;
}
}
void leavemsg(string name)
{
cout<<name<<" has left school.I will leave a message for him."<<endl;
}
private:
map<string,weak_ptr<human>> names; // 传达室的花名册
};
int main()
{
// 学校的学生
map<string,shared_ptr<human>> humans;
humans["Jiawei"] = make_shared<human>("Jiawei");
humans["Chen"] = make_shared<human>("Chen");
humans["Xibei"] = make_shared<human>("Xibei");

// 传达室,根据学生构造一个花名册
doorman dm(humans);
// 有人找Chen
dm.call("Chen");
// 有人找Fu
dm.call("Fu");

// Chen离开学校,对象被析构
humans.erase("Chen");
// 又有人打来电话找Chen,这时他已经不在学校,只能给他留一个消息了
dm.call("Chen");
// 有人找Jiawei,她还在学校呢,直接叫她
dm.call("Jiawei");

return 0;
}
从这段程序的输出,我们也可以看出,我们在删除humans容器中的Chen这个元素是,对应的human对象也被析构,doorman中指向这个对象的weak_ptr并不影响它的析构,当我们再次尝试访问这个对象时候,lock()无法成功获得与之关联的shared_ptr,也就无法对其进行访问了。

Chen was called.
Fu is not in the school.
Chen was destructed.
Chen has left school.I will leave a message for him.
Jiawei was called.
Xibei was destructed.
Jiawei was destructed.

这里大家可能会问,为什么不在doorman中使用裸指针呢?。。。

那么,为什么不直接使用shared_ptr呢? 参考原文。

总结起来,weak_ptr用于访问了那些不具备所有权的,可能存在也可能不存在的对象。

posted on 2011-09-20 16:29 陈良乔——《我的第一本C++书》 阅读(1773) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理