casacore
Loading...
Searching...
No Matches
casacore::details::CyclicPtr< T > Class Template Reference

A smart pointer class that allows to work with complex cycles without using weak_ptrs. More...

#include <CyclicPtr.h>

Classes

struct  Data

Public Member Functions

 CyclicPtr ()=default
 CyclicPtr (std::nullptr_t)
 CyclicPtr (T *object)
 CyclicPtr (const CyclicPtr &source)
 CyclicPtr (CyclicPtr &&source)
 ~CyclicPtr ()
T * Get () const
void Reset ()
CyclicPtroperator= (const CyclicPtr &other)
CyclicPtroperator= (CyclicPtr &&other)
 operator bool () const
T & operator* () const
T * operator-> () const
CyclicState Freeze () const
 Freeze the reference counter.
void Unfreeze (const CyclicState &frozen_state)
 Continue 'normal' reference counting.

Private Member Functions

void Increase ()
void Decrease ()

Private Attributes

std::shared_ptr< Datadata_

Friends

bool operator== (const CyclicPtr< T > &lhs, const CyclicPtr< T > &rhs)
bool operator!= (const CyclicPtr< T > &lhs, const CyclicPtr< T > &rhs)

Detailed Description

template<typename T>
class casacore::details::CyclicPtr< T >

A smart pointer class that allows to work with complex cycles without using weak_ptrs.

Instead, the pointer needs to be manually frozen during the creation of cycles, such that cycle-links are not counted.

This class was specifically written for the MeasFrame class, which can have cycles via various routes. Originally, the FrameRep class held a counter and was destructed when the counter reached zero. While this worked, it had issues:

  • It was hard to understand the implementation. It looked like a "standard" manual reference-counting implementation and it therefore seemed like it could be replaced by a shared_ptr. This class helps to annotate the intention.
  • It had bugs: it would sometimes access the counter after destruction of the MeasFrame (see #1082). By holding the counter inside the pointer class, this is avoided.
  • The counter was not implemented in a safe manner, hence copying the same frame to different threads would cause a race condition even when the frame was only read from (/copied).

Having a separate class that also holds the counter avoids these problems. Introducing weak_ptrs to break the cycles in the measures code has been tried, but probably requires major changes in the structure.

This is an example of how to use the class:

struct Node { CyclicPtr<Node> link; };

CyclicPtr<Node> node = MakeCyclic<Node>();
const CyclicState state = node.Freeze();
node->link = node;
node.Unfreeze(state);

By freezing the state when creating the link, the link is not counted as a reference. As soon as either node->link or node is reset or goes out of scope, the Node object is destroyed and the other CyclicPtr will become nullptr.

This class implements the counter in a thread-safe way, such that the pointer can be copied around in different threads as if it is a normal pointer. Freeze() and Unfreeze() are not thread safe. In the MeasFrame class, these functions are only used during initialization or write-to actions of the MeasFrame, which remains valid.

It should be clear that this is a dangerous class to use correctly.

Definition at line 78 of file CyclicPtr.h.

Constructor & Destructor Documentation

◆ CyclicPtr() [1/5]

template<typename T>
casacore::details::CyclicPtr< T >::CyclicPtr ( )
default

◆ CyclicPtr() [2/5]

template<typename T>
casacore::details::CyclicPtr< T >::CyclicPtr ( std::nullptr_t )
inline

Definition at line 83 of file CyclicPtr.h.

◆ CyclicPtr() [3/5]

template<typename T>
casacore::details::CyclicPtr< T >::CyclicPtr ( T * object)
inlineexplicit

Definition at line 85 of file CyclicPtr.h.

References data_.

◆ CyclicPtr() [4/5]

template<typename T>
casacore::details::CyclicPtr< T >::CyclicPtr ( const CyclicPtr< T > & source)
inline

Definition at line 88 of file CyclicPtr.h.

References CyclicPtr(), data_, and Increase().

◆ CyclicPtr() [5/5]

template<typename T>
casacore::details::CyclicPtr< T >::CyclicPtr ( CyclicPtr< T > && source)
inline

Definition at line 93 of file CyclicPtr.h.

References CyclicPtr(), data_, and casacore::move().

◆ ~CyclicPtr()

template<typename T>
casacore::details::CyclicPtr< T >::~CyclicPtr ( )
inline

Definition at line 96 of file CyclicPtr.h.

References Decrease().

Member Function Documentation

◆ Decrease()

template<typename T>
void casacore::details::CyclicPtr< T >::Decrease ( )
inlineprivate

Definition at line 171 of file CyclicPtr.h.

References data_.

Referenced by operator=(), operator=(), Reset(), and ~CyclicPtr().

◆ Freeze()

template<typename T>
CyclicState casacore::details::CyclicPtr< T >::Freeze ( ) const
inlinenodiscard

Freeze the reference counter.

The object is guaranteed not to be destructed until Unfreeze() is called.

The caller is responsible for calling Unfreeze(); letting CyclicState go out of scope without unfreezing will not cause an error, so will lead to an undetected state error. While it would be possible to detect this, it would increase the size of CyclicState.

Definition at line 144 of file CyclicPtr.h.

References data_.

◆ Get()

template<typename T>
T * casacore::details::CyclicPtr< T >::Get ( ) const
inline

Definition at line 100 of file CyclicPtr.h.

References data_.

◆ Increase()

template<typename T>
void casacore::details::CyclicPtr< T >::Increase ( )
inlineprivate

Definition at line 165 of file CyclicPtr.h.

References data_.

Referenced by CyclicPtr(), and operator=().

◆ operator bool()

template<typename T>
casacore::details::CyclicPtr< T >::operator bool ( ) const
inlineexplicit

Definition at line 122 of file CyclicPtr.h.

References data_.

◆ operator*()

template<typename T>
T & casacore::details::CyclicPtr< T >::operator* ( ) const
inline

Definition at line 124 of file CyclicPtr.h.

References data_.

◆ operator->()

template<typename T>
T * casacore::details::CyclicPtr< T >::operator-> ( ) const
inline

Definition at line 125 of file CyclicPtr.h.

References data_.

◆ operator=() [1/2]

template<typename T>
CyclicPtr & casacore::details::CyclicPtr< T >::operator= ( const CyclicPtr< T > & other)
inline

Definition at line 109 of file CyclicPtr.h.

References CyclicPtr(), data_, Decrease(), and Increase().

◆ operator=() [2/2]

template<typename T>
CyclicPtr & casacore::details::CyclicPtr< T >::operator= ( CyclicPtr< T > && other)
inline

Definition at line 116 of file CyclicPtr.h.

References CyclicPtr(), data_, and Decrease().

◆ Reset()

template<typename T>
void casacore::details::CyclicPtr< T >::Reset ( )
inline

Definition at line 104 of file CyclicPtr.h.

References data_, and Decrease().

◆ Unfreeze()

template<typename T>
void casacore::details::CyclicPtr< T >::Unfreeze ( const CyclicState & frozen_state)
inline

Continue 'normal' reference counting.

Definition at line 151 of file CyclicPtr.h.

References data_, and casacore::details::CyclicState::value_.

◆ operator!=

template<typename T>
bool operator!= ( const CyclicPtr< T > & lhs,
const CyclicPtr< T > & rhs )
friend

Definition at line 131 of file CyclicPtr.h.

References CyclicPtr(), and data_.

◆ operator==

template<typename T>
bool operator== ( const CyclicPtr< T > & lhs,
const CyclicPtr< T > & rhs )
friend

Definition at line 127 of file CyclicPtr.h.

References CyclicPtr(), and data_.

Member Data Documentation

◆ data_

template<typename T>
std::shared_ptr<Data> casacore::details::CyclicPtr< T >::data_
private

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