deal.II version GIT relicensing-2289-g1e5549a87a 2024-12-21 21:30:00+00:00
|
#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< bool > | pointed_to_object_is_alive |
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.
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: dont_do_this
pointer does not trigger the release of the memory pointed to.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.Definition at line 105 of file observer_pointer.h.
|
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.
|
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.
|
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.
|
inlinenoexcept |
Move constructor for ObserverPointer.
Definition at line 382 of file observer_pointer.h.
|
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.
|
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.
|
inline |
Destructor, removing the subscription.
Definition at line 420 of file observer_pointer.h.
|
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.
|
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.
|
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.
|
inlinenoexcept |
Move assignment operator for ObserverPointer.
Definition at line 528 of file observer_pointer.h.
|
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.
Definition at line 434 of file observer_pointer.h.
|
inline |
Conversion to normal pointer.
Definition at line 569 of file observer_pointer.h.
|
inline |
Dereferencing operator. This operator throws an ExcNotInitialized() if the pointer is a null pointer.
Definition at line 578 of file observer_pointer.h.
|
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.
|
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.
|
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.
|
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.
|
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.
|
private |
Pointer to the object we want to subscribe to.
Definition at line 262 of file observer_pointer.h.
|
private |
The identification for the subscriptor.
Definition at line 267 of file observer_pointer.h.
|
private |
The Smartpointer is invalidated when the object pointed to is destroyed or moved from.
Definition at line 273 of file observer_pointer.h.