Weak Pointers and Circular References in C++ 11: Listing 3
Weak_ptr is an exhaust vent for circular references.
// person.h – Correct version (see Figure 2)
#ifndef PERSON_H_
#define PERSON_H_
#include <memory>
#include <string>
using namespace std;
class person {
friend void get_couple_married(shared_ptr<person>, shared_ptr<person>);
public:
person() = delete;
person(const string);
~person();
string get_name() const;
shared_ptr<person> get_spouse() const;
private:
// nested class that models a smart pointer that could be strong or weak
class spouse_ptr {
private:
shared_ptr<person> strong_;
weak_ptr<person> weak_;
spouse_ptr& set(const shared_ptr<person>);
public:
spouse_ptr();
spouse_ptr(const shared_ptr<person>);
spouse_ptr& operator=(const shared_ptr<person>);
shared_ptr<person> get() const;
};
string name_;
spouse_ptr spouse_;
void set_spouse(const shared_ptr<person>);
};
#endif /* PERSON_H_ */
/* ---------------------------------- */
// person.cpp
#include "person.h"
#include <iostream>
#include <stdexcept>
using namespace std;
person::person(const string name) : name_{name} {
cout << name_ << " instance created." << endl;
}
person::~person() {
cout << name_ << " instance to be disposed." << endl;
}
string person::get_name() const { return name_; }
shared_ptr<person> person::get_spouse() const { return this->spouse_.get(); }
void person::set_spouse(const shared_ptr<person> sp) {
this->spouse_ = sp;
}
person::spouse_ptr::spouse_ptr() : strong_{nullptr}, weak_{} {}
person::spouse_ptr::spouse_ptr(const shared_ptr<person> sp) : strong_{nullptr}, weak_{} {
set(sp);
}
person::spouse_ptr& person::spouse_ptr::operator=(const shared_ptr<person> sp) {
return set(sp);
}
shared_ptr<person> person::spouse_ptr::get() const {
if (strong_!=nullptr)
return strong_;
else
return weak_.lock();
}
person::spouse_ptr& person::spouse_ptr::set(const shared_ptr<person> sp) {
// the strong or weak reference is used depending on
if (sp->get_spouse()==nullptr) {
strong_ = sp;
weak_.reset();
} else {
strong_ = nullptr;
weak_ = sp;
}
return *this;
}
void get_couple_married(shared_ptr<person> husband, shared_ptr<person> wife) {
// checks arguments aren’t null
if ((husband==nullptr)||(wife==nullptr))
throw invalid_argument("get_couple_married(husband, wife): can't get nullptr as couple member");
// checks arguments aren’t the same instance
if (husband.get()==wife.get())
throw invalid_argument("get_couple_married(husband, wife): husband and wife can't be the same person");
// the husband strongly points to his wife, while she weakly points back to him
// (see function person::spouse_ptr::set)
husband->set_spouse(wife);
wife->set_spouse(husband);
}
/* ---------------------------------- */
// main.cpp
#include <iostream>
#include "person.h"
using namespace std;
void get_couple_married() {
shared_ptr<person> husband = make_shared<person>("John"), wife = make_shared<person>("Pocahontas");
get_couple_married(husband, wife);
cout << husband->get_name() << "'s wife is " << husband->get_spouse()->get_name() << "." << endl;
cout << wife->get_name() << "'s husband is " << wife->get_spouse()->get_name() << "." << endl;
}
int main() {
get_couple_married();
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].