deal.II version GIT relicensing-2289-g1e5549a87a 2024-12-21 21:30:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
Public Member Functions | Private Attributes | List of all members
ObserverPointer< T, P > Class Template Reference

#include <deal.II/base/observer_pointer.h>

Public Member Functions

 ObserverPointer ()
 
template<class Q >
 ObserverPointer (const ObserverPointer< T, Q > &other)
 
 ObserverPointer (const ObserverPointer< T, P > &other)
 
 ObserverPointer (ObserverPointer< T, P > &&other) noexcept
 
 ObserverPointer (T *t, const std::string &id)
 
 ObserverPointer (T *t)
 
 ~ObserverPointer ()
 
ObserverPointer< T, P > & operator= (T *tt)
 
template<class Q >
ObserverPointer< T, P > & operator= (const ObserverPointer< T, Q > &other)
 
ObserverPointer< T, P > & operator= (const ObserverPointer< T, P > &other)
 
ObserverPointer< T, P > & operator= (ObserverPointer< T, P > &&other) noexcept
 
void clear ()
 
 operator T* () const
 
T & operator* () const
 
T * get () const
 
T * operator-> () const
 
template<class Q >
void swap (ObserverPointer< T, Q > &tt)
 
void swap (T *&ptr)
 
std::size_t memory_consumption () const
 

Private Attributes

T * pointer
 
const std::string id
 
std::atomic< boolpointed_to_object_is_alive
 

Detailed Description

template<typename T, typename P = void>
class ObserverPointer< T, P >

This class represents an "observer pointer", i.e., it is a pointer class like std::unique_ptr or std::shared_ptr, but it does not participate in managing the lifetime of the object pointed to – we are simply observing an object passively that is owned by some other entity of the program, but we are not in charge of creating and destroying this object. In particular, the pointer may be pointing to a member variable of another object whose lifetime is not actively managed but is instead tied to the lifetime of the surrounding object of which it is a member.

The class does, however, have mechanisms to ensure that the object pointed to remains alive at least as long as the pointer points to – in other words, unlike a simple C-style T* variable, it can avoid the problem of dangling pointers. In other works, objects of the current type can be used like a regular pointer (i.e., using the *p and p-> operators and through casting), but they make sure that the object pointed to is not deleted or moved from in the course of use of the pointer by signaling the pointee its use. This is achieved by keeping a use count for the pointed-to object (which for this purpose needs to be derived from the EnableObserverPointer class), and ensuring that the pointed-to object's destructor triggers an error if that use-count is larger than zero – i.e., if there are still observing ObserverPointer objects pointing to it.

Conceptually, ObserverPointer fills a gap between std::unique_ptr and std::shared_ptr. While the former makes it clear that there is a unique owner of an object (namely the scope in which the std::unique_ptr resides), it does not allow other places in a code base to point to the object. In contrast, std::shared_ptr allows many places to point to the same object, but none of them is the "owner" of the object: They all are, and the last one to stop pointing to the object is responsible for deleting it.

ObserverPointer utilizes semantics in which one place owns an object and others can point to it. The owning place is responsible for destroying the object when it is no longer needed, and as mentioned above, this will trigger an error if other places are still pointing to it via ObserverPointer pointers.

In practice, using this scheme, if you try to destroy an object to which observers still point via ObserverPointer objects, you will get an error that says that there are still observers of the object and that the object can consequently not be destroyed without creating "dangling" pointers. This is often not very helpful in finding where these pointers are. As a consequence, this class also provides two ways to annotate the observer count with information about what other places still observe an object. First, when initializing a ObserverPointer object with the address of the object pointed to, you can also attach a string that describes the observing location, and this string will then be shown in error messages listing all remaining observers. Second, if no such string is provided, the name second template argument P is used as the debug string. This allows to encode the observer information in the type of the ObserverPointer.

Note
Unlike std::unique_ptr and std::shared_ptr, ObserverPointer does NOT implement any memory handling. In particular, deleting a ObserverPointer does not delete the object because the semantics of this class are that it only observes an object, but does not take over ownership. As a consequence, this is a sure way of creating a memory leak: This is because here, no variable "owns" the object pointed to, and the destruction of the dont_do_this pointer does not trigger the release of the memory pointed to.
This class correctly handles const-ness of an object, i.e., a ObserverPointer<const T> really behaves as if it were a pointer to a constant object (disallowing write access when dereferenced), while ObserverPointer<T> is a mutable pointer.
This class, function, or variable is a template, and it can only be instantiated if the following condition is true: If your compiler supports the C++20 standard, then this constraint will be enforced by a C++20 requires clause.

Definition at line 105 of file observer_pointer.h.

Constructor & Destructor Documentation

◆ ObserverPointer() [1/6]

template<typename T , typename P >
ObserverPointer< T, P >::ObserverPointer ( )
inline

Standard constructor for null pointer. The id of this pointer is set to the name of the class P.

Definition at line 292 of file observer_pointer.h.

◆ ObserverPointer() [2/6]

template<typename T , typename P >
template<class Q >
ObserverPointer< T, P >::ObserverPointer ( const ObserverPointer< T, Q > &  other)
inline

Copy constructor for ObserverPointer. We do not copy the object subscribed to from tt, but subscribe ourselves to it again.

Definition at line 338 of file observer_pointer.h.

◆ ObserverPointer() [3/6]

template<typename T , typename P >
ObserverPointer< T, P >::ObserverPointer ( const ObserverPointer< T, P > &  other)
inline

Copy constructor for ObserverPointer. We do not copy the object subscribed to from tt, but subscribe ourselves to it again.

Definition at line 360 of file observer_pointer.h.

◆ ObserverPointer() [4/6]

template<typename T , typename P >
ObserverPointer< T, P >::ObserverPointer ( ObserverPointer< T, P > &&  other)
inlinenoexcept

Move constructor for ObserverPointer.

Definition at line 382 of file observer_pointer.h.

◆ ObserverPointer() [5/6]

template<typename T , typename P >
ObserverPointer< T, P >::ObserverPointer ( T *  t,
const std::string &  id 
)
inline

Constructor taking a normal pointer. If possible, i.e. if the pointer is not a null pointer, the constructor subscribes to the given object to lock it, i.e. to prevent its destruction before the end of its use.

The id is used in the call to EnableObserverPointer::subscribe(id) and by ~ObserverPointer() in the call to EnableObserverPointer::unsubscribe().

Definition at line 321 of file observer_pointer.h.

◆ ObserverPointer() [6/6]

template<typename T , typename P >
ObserverPointer< T, P >::ObserverPointer ( T *  t)
inline

Constructor taking a normal pointer. If possible, i.e. if the pointer is not a null pointer, the constructor subscribes to the given object to lock it, i.e. to prevent its destruction before the end of its use. The id of this pointer is set to the name of the class P.

Definition at line 305 of file observer_pointer.h.

◆ ~ObserverPointer()

template<typename T , typename P >
ObserverPointer< T, P >::~ObserverPointer ( )
inline

Destructor, removing the subscription.

Definition at line 420 of file observer_pointer.h.

Member Function Documentation

◆ operator=() [1/4]

template<typename T , typename P >
ObserverPointer< T, P > & ObserverPointer< T, P >::operator= ( T *  tt)
inline

Assignment operator for normal pointers. The pointer subscribes to the new object automatically and unsubscribes to an old one if it exists. It will not try to subscribe to a null-pointer, but still delete the old subscription.

Definition at line 449 of file observer_pointer.h.

◆ operator=() [2/4]

template<typename T , typename P >
template<class Q >
ObserverPointer< T, P > & ObserverPointer< T, P >::operator= ( const ObserverPointer< T, Q > &  other)
inline

Assignment operator for ObserverPointer. The pointer subscribes to the new object automatically and unsubscribes to an old one if it exists.

Definition at line 472 of file observer_pointer.h.

◆ operator=() [3/4]

template<typename T , typename P >
ObserverPointer< T, P > & ObserverPointer< T, P >::operator= ( const ObserverPointer< T, P > &  other)
inline

Assignment operator for ObserverPointer. The pointer subscribes to the new object automatically and unsubscribes to an old one if it exists.

Definition at line 500 of file observer_pointer.h.

◆ operator=() [4/4]

template<typename T , typename P >
ObserverPointer< T, P > & ObserverPointer< T, P >::operator= ( ObserverPointer< T, P > &&  other)
inlinenoexcept

Move assignment operator for ObserverPointer.

Definition at line 528 of file observer_pointer.h.

◆ clear()

template<typename T , typename P >
void ObserverPointer< T, P >::clear ( )
inline

Delete the object pointed to and set the pointer to nullptr. Note that unlike what the documentation of the class describes, this function actually deletes the object pointed to. That is, this function assumes a ObserverPointer's ownership of the object pointed to.

Deprecated:
This function is deprecated. It does not use the semantics we usually use for this class, and its use is surely going to be confusing.

Definition at line 434 of file observer_pointer.h.

◆ operator T*()

template<typename T , typename P >
ObserverPointer< T, P >::operator T* ( ) const
inline

Conversion to normal pointer.

Definition at line 569 of file observer_pointer.h.

◆ operator*()

template<typename T , typename P >
T & ObserverPointer< T, P >::operator* ( ) const
inline

Dereferencing operator. This operator throws an ExcNotInitialized() if the pointer is a null pointer.

Definition at line 578 of file observer_pointer.h.

◆ get()

template<typename T , typename P >
T * ObserverPointer< T, P >::get ( ) const
inline

Return underlying pointer. This operator throws an ExcNotInitialized() if the pointer is a null pointer.

Definition at line 590 of file observer_pointer.h.

◆ operator->()

template<typename T , typename P >
T * ObserverPointer< T, P >::operator-> ( ) const
inline

Operator that returns the underlying pointer. This operator throws an ExcNotInitialized() if the pointer is a null pointer.

Definition at line 602 of file observer_pointer.h.

◆ swap() [1/2]

template<typename T , typename P >
template<class Q >
void ObserverPointer< T, P >::swap ( ObserverPointer< T, Q > &  tt)
inline

Exchange the pointers of this object and the argument. Since both the objects to which is pointed are subscribed to before and after, we do not have to change their subscription counters.

Note that this function (with two arguments) and the respective functions where one of the arguments is a pointer and the other one is a C-style pointer are implemented in global namespace.

Definition at line 612 of file observer_pointer.h.

◆ swap() [2/2]

template<typename T , typename P >
void ObserverPointer< T, P >::swap ( T *&  ptr)
inline

Swap pointers between this object and the pointer given. As this releases the object pointed to presently, we reduce its subscription count by one, and increase it at the object which we will point to in the future.

Note that we indeed need a reference of a pointer, as we want to change the pointer variable which we are given.

Definition at line 627 of file observer_pointer.h.

◆ memory_consumption()

template<typename T , typename P >
std::size_t ObserverPointer< T, P >::memory_consumption ( ) const
inline

Return an estimate of the amount of memory (in bytes) used by this class. Note in particular, that this only includes the amount of memory used by this object, not by the object pointed to.

Definition at line 642 of file observer_pointer.h.

Member Data Documentation

◆ pointer

template<typename T , typename P = void>
T* ObserverPointer< T, P >::pointer
private

Pointer to the object we want to subscribe to.

Definition at line 262 of file observer_pointer.h.

◆ id

template<typename T , typename P = void>
const std::string ObserverPointer< T, P >::id
private

The identification for the subscriptor.

Definition at line 267 of file observer_pointer.h.

◆ pointed_to_object_is_alive

template<typename T , typename P = void>
std::atomic<bool> ObserverPointer< T, P >::pointed_to_object_is_alive
private

The Smartpointer is invalidated when the object pointed to is destroyed or moved from.

Definition at line 273 of file observer_pointer.h.


The documentation for this class was generated from the following file: