158 lines
3.7 KiB
C++
158 lines
3.7 KiB
C++
// vi:set ft=cpp: -*- Mode: C++ -*-
|
|
/*
|
|
* Copyright (C) 2015, 2017, 2024 Kernkonzept GmbH.
|
|
* Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
|
|
* Alexander Warg <alexander.warg@kernkonzept.com>
|
|
*
|
|
* License: see LICENSE.spdx (in this directory or the directories above)
|
|
*/
|
|
#pragma once
|
|
|
|
#include "hlist"
|
|
|
|
namespace cxx {
|
|
|
|
/**
|
|
* Generic (base) weak reference to some object.
|
|
*
|
|
* A weak reference is a reference that gets reset to NULL when the object
|
|
* shall be deleted. All weak references to the same object are kept in a
|
|
* linked list of weak references.
|
|
*
|
|
* For typed weak references see `cxx::Weak_ref`.
|
|
*/
|
|
class Weak_ref_base : public H_list_item_t<Weak_ref_base>
|
|
{
|
|
protected:
|
|
Weak_ref_base(void const *ptr = nullptr) : _obj(ptr) {}
|
|
void reset_hard() { _obj = nullptr; }
|
|
void const *_obj;
|
|
|
|
public:
|
|
/**
|
|
* The list type for keeping all weak references to an object.
|
|
*
|
|
* On destruction of a list, all weak references to the respective object are
|
|
* set to `nullptr`.
|
|
*/
|
|
struct List : H_list_t<Weak_ref_base>
|
|
{
|
|
void reset()
|
|
{
|
|
while (!empty())
|
|
pop_front()->reset_hard();
|
|
}
|
|
|
|
~List()
|
|
{ reset(); }
|
|
};
|
|
|
|
explicit operator bool () const
|
|
{ return _obj ? true : false; }
|
|
};
|
|
|
|
|
|
/**
|
|
* Typed weak reference to an object of type `T`.
|
|
*
|
|
* \tparam T The type of the referenced object.
|
|
*
|
|
* A weak reference is a reference that is invalidated when the referenced
|
|
* object is about to be deleted. All weak references to an object are kept in
|
|
* a linked list (see Weak_ref_base::List) and all the weak references are
|
|
* iterated and reset by the Weak_ref_base::List destructor or
|
|
* Weak_ref_base::List::reset().
|
|
*
|
|
* The type `T` must provide two methods that handle the housekeeping of weak
|
|
* references: `remove_weak_ref(Weak_ref_base *)` and
|
|
* `add_weak_ref(Weak_ref_base *)`. These functions must handle the insertion
|
|
* and removal of the weak reference into the respective Weak_ref_base::List
|
|
* object. For convenience one can use the cxx::Weak_ref_obj as a base class
|
|
* that handles weak references for you.
|
|
*
|
|
* For example:
|
|
* ```{.cpp}
|
|
* class C : public cxx::Weak_ref_obj {};
|
|
*
|
|
* int main()
|
|
* {
|
|
* cxx::Weak_ref<C> r; // r is nullptr
|
|
* {
|
|
* C c;
|
|
* r = &c; // now r points to c
|
|
* } // c is destructed, which implies resetting all weak references to c
|
|
* // now r is nullptr
|
|
* return 0;
|
|
* }
|
|
* ```
|
|
*
|
|
* \note Weak references have no effect on the lifetime of the referenced
|
|
* object. Hence, a referenced object is *not* deleted when all weak
|
|
* references for it are gone. If automatic deletion is needed, see
|
|
* cxx::Ref_ptr.
|
|
*/
|
|
template <typename T>
|
|
class Weak_ref : public Weak_ref_base
|
|
{
|
|
public:
|
|
T *get() const
|
|
{ return reinterpret_cast<T*>(const_cast<void *>(_obj)); }
|
|
|
|
T *reset(T *n)
|
|
{
|
|
T *r = get();
|
|
if (r)
|
|
r->remove_weak_ref(this);
|
|
|
|
_obj = n;
|
|
if (n)
|
|
n->add_weak_ref(this);
|
|
|
|
return r;
|
|
}
|
|
|
|
Weak_ref(T *s = nullptr) : Weak_ref_base(s)
|
|
{
|
|
if (s)
|
|
s->add_weak_ref(this);
|
|
}
|
|
|
|
~Weak_ref() { reset(0); }
|
|
|
|
void operator = (T *n)
|
|
{ reset(n); }
|
|
|
|
Weak_ref(Weak_ref const &o) : Weak_ref_base(o._obj)
|
|
{
|
|
if (T *x = get())
|
|
x->add_weak_ref(this);
|
|
}
|
|
|
|
Weak_ref &operator = (Weak_ref const &o)
|
|
{
|
|
if (&o == this)
|
|
return *this;
|
|
|
|
reset(o.get());
|
|
return *this;
|
|
}
|
|
|
|
T &operator * () const { return get(); }
|
|
T *operator -> () const { return get(); }
|
|
};
|
|
|
|
class Weak_ref_obj
|
|
{
|
|
protected:
|
|
template <typename T> friend class Weak_ref;
|
|
mutable Weak_ref_base::List weak_references;
|
|
|
|
void add_weak_ref(Weak_ref_base *ref) const
|
|
{ weak_references.push_front(ref); }
|
|
|
|
void remove_weak_ref(Weak_ref_base *ref) const
|
|
{ weak_references.remove(ref); }
|
|
};
|
|
|
|
}
|