Rule A20-8-7 (required, implementation, non-automated)

A std::weak_ptr shall be used to represent temporary shared ownership.

Rationale

A cyclic structure of std::shared_ptr results in reference counting mechanism never dropping to zero, which prevents from pointed object deallocation. Breaking such

cycles is done using std::weak_ptr which must be converted to std::shared_ptr in order to access the referenced object.

Example

// $Id: A20-8-7.cpp 308795 2018-02-23 09:27:03Z michal.szczepankiewicz $ #include <memory> template <template <typename> class T, typename U> struct Base { T<U> sp; }; template <typename T> using Shared = Base<std::shared_ptr, T>; template <typename T> using Weak = Base<std::weak_ptr, T>; struct SBarSFoo; struct SFooSBar : public Shared<SBarSFoo> {}; struct SBarSFoo : public Shared<SFooSBar> {}; struct A : public Shared<A> {}; struct WBarSFoo; struct SFooWBar : public Shared<WBarSFoo> {}; struct WBarSFoo : public Weak<SFooWBar> {}; int main() { std::shared_ptr<SFooSBar> f = std::make_shared<SFooSBar>(); std::shared_ptr<SBarSFoo> b = std::make_shared<SBarSFoo>(); f->sp = b; b->sp = f; //non-compliant, both f and b have ref_count() == 2 //destructors of f and b reduce ref_count() to 1, //destructors of underlying objects are never called, //so destructors of shared_ptrs sp are not called //and memory is leaked std::shared_ptr<A> a = std::make_shared<A>(); a->sp = a; //non-compliant, object ’a’ destructor does not call //underlying memory destructor std::shared_ptr<SFooWBar> f2 = std::make_shared<SFooWBar>(); std::shared_ptr<WBarSFoo> b2 = std::make_shared<WBarSFoo>(); f2->sp = b2; b2->sp = f2; //compliant, b2->sp holds weak_ptr to f2, so f2 destructor //is able to properly destroy underlying object return 0; }

See also

C++ Core Guidelines [11]: R.24: Use std::weak_ptr to break cycles of shared_ptrs