Weak Pointers and Circular References in C++ 11: Listing 6
Restricting circular references to a conceptual level.
#ifndef PERSON_H_
#define PERSON_H_
#include <string>
#include <memory>
#include <map>
using namespace std;
class person;
// this class models a table of friendship (name, best friend)
class friendship {
public:
void set_best_friend(shared_ptr<person>, const shared_ptr<person>);
shared_ptr<person> get_best_friend(const shared_ptr<person>) const;
void set_no_best_friend(shared_ptr<person>);
private:
// hashtable
map<string, shared_ptr<person>> container_;
};
class person {
public:
person()=delete;
person(const string);
~person();
string get_name() const;
private:
string name_;
};
#endif /* PERSON_H_ */
/* ---------------------------------- */
// person.cpp
#include "person.h"
#include <iostream>
#include <stdexcept>
using namespace std;
void friendship::set_best_friend(shared_ptr<person> p, const shared_ptr<person> best_friend) {
if (p.get()==best_friend.get())
throw invalid_argument("Best friend can't be self person");
auto name = p->get_name();
container_.erase(name);
if (best_friend)
container_[name] = best_friend;
}
shared_ptr<person> friendship::get_best_friend(const shared_ptr<person> p) const {
auto i = container_.find(p->get_name());
if (i==end(container_))
return nullptr;
else
return i->second;
}
void friendship::set_no_best_friend(shared_ptr<person> p) {
set_best_friend(p, nullptr);
}
person::person(const string name) : name_ {name} {
if (name_=="") throw invalid_argument("A person must have a non-empty name");
cout << name_ << " instance created." << endl;
}
person::~person() {
cout << name_ << " instance to be disposed." << endl;
}
string person::get_name() const {
return name_;
}
/* ---------------------------------- */
// main.cpp
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include "person.h"
using namespace std;
void print_friendship(const vector<shared_ptr<person>> &vp, const friendship& f) {
for (auto p : vp) {
auto q = f.get_best_friend(p);
cout << p->get_name() << "'s best friend is " << (q ? q->get_name() : "nobody") << endl;
}
}
void make_friends() {
shared_ptr<person> john = make_shared<person>("John"),
charles = make_shared<person>("Charles"),
emma = make_shared<person>("Emma"),
cindy = make_shared<person>("Cindy"),
arthur = make_shared<person>("Arthur"),
laurie = make_shared<person>("Laurie");
friendship f;
vector<shared_ptr<person>> vp = {john, charles, emma, cindy, arthur, laurie};
// now friendship is kept outside person instances, to eliminate all chance of circular
// references
f.set_best_friend(john, charles);
f.set_best_friend(charles, emma);
f.set_best_friend(emma, cindy);
f.set_best_friend(cindy, arthur);
f.set_best_friend(arthur, laurie);
f.set_best_friend(laurie, john);
print_friendship(vp, f);
f.set_best_friend(cindy, charles);
print_friendship(vp, f);
f.set_best_friend(john, cindy);
f.set_best_friend(emma, arthur);
print_friendship(vp, f);
f.set_no_best_friend(charles);
print_friendship(vp, f);
}
int main() {
make_friends();
return 0;
}
About the Author
Diego Dagum is a software architect and developer with more than 20 years of experience. He can be reached at [email protected].