Weak Pointers and Circular References in C++ 11: Listing 5
People and their best friends: a non-deterministic circular reference example.
// person.h
#ifndef PERSON_H_
#define PERSON_H_
#include <string>
#include <memory>
#include "circular_ptr.h"
using namespace std;
class person {
friend circular_ptr<person> *get_circular_ptr(const shared_ptr<person>&);
public:
person()=delete;
person(const string);
~person();
string get_name() const;
void set_best_friend(shared_ptr<person>);
shared_ptr<person> get_best_friend() const;
void set_no_best_friend();
private:
class best_friend_ptr : public circular_ptr<person> {
public:
best_friend_ptr();
best_friend_ptr(shared_ptr<person>&);
best_friend_ptr& operator=(shared_ptr<person>&);
};
string name_;
best_friend_ptr best_friend_;
};
#endif /* PERSON_H_ */
/* ---------------------------------- */
// person.cpp
#include "person.h"
#include <iostream>
#include <stdexcept>
using namespace std;
person::person(const string name) : name_ {name}, best_friend_ {} {
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_;
}
void person::set_best_friend(shared_ptr<person> best_friend) {
if (this==best_friend.get())
throw invalid_argument("Best friend can't be self person");
best_friend_ = best_friend;
}
shared_ptr<person> person::get_best_friend() const {
return best_friend_.get();
}
void person::set_no_best_friend() {
best_friend_.reset();
}
person::best_friend_ptr::best_friend_ptr() : circular_ptr::circular_ptr() {}
person::best_friend_ptr::best_friend_ptr(shared_ptr<person> &p) : circular_ptr::circular_ptr(p) {}
person::best_friend_ptr& person::best_friend_ptr::operator=(shared_ptr<person> &t) {
return static_cast<person::best_friend_ptr&>(circular_ptr::operator=(t));
}
circular_ptr<person> *get_circular_ptr(const shared_ptr<person> &p) {
return &(p->best_friend_);
}
/* ---------------------------------- */
// main.cpp
#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include "person.h"
using namespace std;
void print_friendship(vector<shared_ptr<person>> vp) {
for (auto p : vp) {
auto q = p->get_best_friend();
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");
vector<shared_ptr<person>> vp = {john, charles, emma, cindy, arthur, laurie};
john->set_best_friend(charles); // strong
charles->set_best_friend(emma); // strong
emma->set_best_friend(cindy); // strong
cindy->set_best_friend(arthur); // strong
arthur->set_best_friend(laurie); // strong
laurie->set_best_friend(john); // weak! See Figure 3
print_friendship(vp);
cindy->set_best_friend(charles); // weak, but also laurie’s ptr to john
// becomes strong (see Figure 4)
print_friendship(vp);
john->set_best_friend(cindy); // strong
emma->set_best_friend(arthur); // weak, but also cindy’s ptr to charles
// becomes strong (see Figure 5)
print_friendship(vp);
charles->set_no_best_friend(); // emma’s ptr to arthur becomes strong
print_friendship(vp); // See Figure 6
}
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].