分类:c++| 发布时间:2015-11-09 23:17:00
shared_ptr 适用于大部分的情况,但也有其局限性。 其中一个是不能正确处理循环引用的情况。
先来看一个例子:
#include <memory>
#include <vector>
#include <iostream>
using namespace std;
struct Person;
struct Team {
Team() { cout << "Team constructor" << endl; }
~Team() { cout << "Team destructor" << endl; }
vector<shared_ptr<Person> > persons;
};
struct Person {
Person() { cout << "Person constructor" << endl; }
~Person() { cout << "Person destructor" << endl; }
shared_ptr<Team> team;
};
int main()
{
shared_ptr<Team> pt(new Team());
shared_ptr<Person> pp(new Person());
pt->persons.push_back(pp);
pp->team = pt;
return 0;
}
// vim: set et ts=4 sts=4 sw=4:
这里有两个类 Team 和 Person。 其中 Team 有个 persons 引用了 Person,而 Person 里面有一个 team 成员指向他所属的组。 然后来看看运行结果:
Team constructor
Person constructor
可以发现 Team 跟 Person 都没正常释放。 这是为什么呢? 由于 Team 和 Person 都有一个引用到对方的成员变量, 因此当执行了:
pt->persons.push_back(pp);
pp->team = pt;
pt 和 pp 的引用计数都是 2,当退出 main 函数后 pt 和 pp 析构,引用计数各减 1。 因此 pp 和 pt 都不会释放。
我们应该怎么解决这个问题呢? 一个比较直观的解决方法是将 Person 里的 team 变成原始指针。 当然这样又会引入其他的问题:当 Team 析构后,Person 的 team 就成了野指针了, 而我们没有办法知道他是一个已经无效的指针。
通过引入弱指针可以解决这个问题。
std::weak_ptr 是一个保存由 std::shared_ptr 管理的对象的非拥有(弱)引用的智能指针。 在访问所引用的对象之前必须要先将其转换为 std::shared_ptr。
现在使用 std::weak_ptr 来改写上面的例子:
#include <memory>
#include <vector>
#include <iostream>
using namespace std;
struct Person;
struct Team {
Team() { cout << "Team constructor" << endl; }
~Team() { cout << "Team destructor" << endl; }
vector<shared_ptr<Person> > persons;
};
struct Person {
Person() { cout << "Person constructor" << endl; }
~Person() { cout << "Person destructor" << endl; }
weak_ptr<Team> team;
};
int main()
{
shared_ptr<Team> pt(new Team());
shared_ptr<Person> pp(new Person());
pt->persons.push_back(pp);
pp->team = pt;
return 0;
}
// vim: set et ts=4 sts=4 sw=4:
输出为:
Team constructor
Person constructor
Team destructor
Person destructor
可以看到可以正确释放资源。
下面我们再来演示下如何通过 std::weak_ptr 访问所引用的对象。
#include <memory>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct Person;
struct Team {
Team() { cout << "Team constructor" << endl; }
~Team() { cout << "Team destructor" << endl; }
vector<shared_ptr<Person> > persons;
string name;
};
struct Person {
Person() { cout << "Person constructor" << endl; }
~Person() { cout << "Person destructor" << endl; }
weak_ptr<Team> team;
string name;
void show() {
shared_ptr<Team> t = team.lock();
if (!t) {
cout << "Team not found" << endl;
return;
}
cout << name << " in " << t->name << endl;
}
};
int main()
{
shared_ptr<Team> pt(new Team());
shared_ptr<Person> pp(new Person());
pt->name = "Test team";
pt->persons.push_back(pp);
pp->team = pt;
pp->name = "Jack";
pp->show();
return 0;
}
// vim: set et ts=4 sts=4 sw=4:
输出为:
Team constructor
Person constructor
Jack in Test team
Team destructor
Person destructor
在这里我们先对 weak_ptr 使用 lock() 返回对应的 shared_ptr 然后检查 shared_ptr 是否有效(检查通过 weak_ptr 返回的 shared_ptr 是一个好习惯, 除非你能确保返回的 shared_ptr 是有效的。)然后输出我们需要的信息。