HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
refPtr.h File Reference
#include "pxr/pxr.h"
#include "pxr/base/tf/diagnosticLite.h"
#include "pxr/base/tf/hash.h"
#include "pxr/base/tf/nullPtr.h"
#include "pxr/base/tf/refBase.h"
#include "pxr/base/tf/safeTypeCompare.h"
#include "pxr/base/tf/typeFunctions.h"
#include "pxr/base/tf/api.h"
#include "pxr/base/arch/hints.h"
#include <typeinfo>
#include <type_traits>
#include <cstddef>
+ Include dependency graph for refPtr.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  Tf_SupportsUniqueChanged< T >
 
struct  Tf_SupportsUniqueChanged< Tf_Remnant >
 
class  TfWeakPtr< T >
 
class  TfWeakPtrFacade< X, Y >
 
struct  Tf_RefPtr_UniqueChangedCounter
 
struct  Tf_RefPtr_Counter
 
class  TfRefPtr< T >
 
struct  TfRefPtr< T >::Rebind< U >
 
class  TfRefPtr< TfRefBase >
 
class  TfRefPtr< const TfRefBase >
 
struct  TfTypeFunctions< TfRefPtr< T > >
 
struct  TfTypeFunctions< TfRefPtr< const T > >
 

Namespaces

 hboost
 

Macros

#define TF_SUPPORTS_REFPTR(T)   std::is_base_of_v<TfRefBase, T>
 

Functions

void Tf_RefPtrTracker_FirstRef (const void *, const void *)
 
void Tf_RefPtrTracker_LastRef (const void *, const void *)
 
void Tf_RefPtrTracker_New (const void *, const void *)
 
void Tf_RefPtrTracker_Delete (const void *, const void *)
 
void Tf_RefPtrTracker_Assign (const void *, const void *, const void *)
 
TF_API void Tf_PostNullSmartPtrDereferenceFatalError (const TfCallContext &, const char *)
 
template<class T >
bool operator== (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator== (std::nullptr_t, const TfRefPtr< T > &p)
 
template<class T >
bool operator!= (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator!= (std::nullptr_t, const TfRefPtr< T > &p)
 
template<class T >
bool operator< (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator< (std::nullptr_t, const TfRefPtr< T > &p)
 
template<class T >
bool operator<= (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator<= (std::nullptr_t, const TfRefPtr< T > &p)
 
template<class T >
bool operator> (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator> (std::nullptr_t, const TfRefPtr< T > &p)
 
template<class T >
bool operator>= (const TfRefPtr< T > &p, std::nullptr_t)
 
template<class T >
bool operator>= (std::nullptr_t, const TfRefPtr< T > &p)
 
template<typename T >
TfRefPtr< T > TfCreateRefPtr (T *ptr)
 
template<class T >
const std::type_info & TfTypeid (const TfRefPtr< T > &ptr)
 
template<class D , class T >
TfRefPtr< typename D::DataType > TfDynamic_cast (const TfRefPtr< T > &ptr)
 
template<class D , class T >
TfRefPtr< typename D::DataType > TfSafeDynamic_cast (const TfRefPtr< T > &ptr)
 
template<class D , class T >
TfRefPtr< typename D::DataType > TfStatic_cast (const TfRefPtr< T > &ptr)
 
template<class T >
TfRefPtr< typename T::DataType > TfConst_cast (const TfRefPtr< const typename T::DataType > &ptr)
 
template<class T >
void swap (TfRefPtr< T > &lhs, TfRefPtr< T > &rhs)
 
template<typename T >
T * hboost::get_pointer (PXR_NS::TfRefPtr< T > const &p)
 
template<class T >
PXR_NAMESPACE_OPEN_SCOPE size_t hash_value (const TfRefPtr< T > &ptr)
 
template<class HashState , class T >
void TfHashAppend (HashState &h, const TfRefPtr< T > &ptr)
 

Detailed Description

Reference counting.

Quick Start

Here is how to make a class Bunny usable through TfRefPtr.

typedef TfRefPtr<Bunny> BunnyRefPtr;
class Bunny : public TfRefBase {
public:
static BunnyRefPtr New() {
// warning: return new Bunny directly will leak memory!
return TfCreateRefPtr(new Bunny);
}
static BunnyRefPtr New(bool isRabid) {
return TfCreateRefPtr(new Bunny(isRabid));
}
~Bunny();
bool IsHungry();
private:
Bunny();
Bunny(bool);
};
BunnyRefPtr nice = Bunny::New();
BunnyRefPtr mean = Bunny::New(true); // this one is rabid
BunnyRefPtr mean2 = mean; // two references to mean rabbit
mean.Reset(); // one reference to mean rabbit
if (mean2->IsHungry())
nice.Reset(); // nice bunny gone now...
// this function comes from
// TfRefBase; meaning is that
if (mean2->IsUnique()) // mean2 is the last pointer to
mean2.Reset(); // this bunny...

Pretty much any pointer operation that is legal with regular pointers is legal with the BunnyRefPtr; continue reading for a more detailed description.

Note that by virtue of deriving from TfRefBase, the reference count can be queried: see TfRefBase for details.

Detailed Discussion: Overview

Objects created by the new operator can easily be a source of both memory leaks and dangling pointers. One solution is reference counting; when an object is created by new, the number of pointers given the object's address is continually tracked in a reference counter. Then, delete is called on the object only when the object's reference count drops to zero, meaning there are no more pointers left pointing to the object. Reference counting avoids both dangling pointers and memory leaks.

Access by regular pointers does not perform reference counting, but the TfRefPtr<T> class implements reference-counted pointer access to objects of type T, with minimal overhead. The reference counting is made thread-safe by use of atomic integers.

Basic Use

The use of a TfRefPtr is simple. Whenever a TfRefPtr is made to point at an object, either by initialization or assignment, the object being pointed at has its reference count incremented. When a TfRefPtr with a non-NULL address is reassigned, or goes out of scope, the object being pointed to has its reference count decremented.

A TfRefPtr<T> can access T's public members by the -> operator and can be dereferenced by the "\c *" operator. Here is a simple example:

typedef TfRefPtr<Simple> SimpleRefPtr;
class Simple : public TfRefBase {
public:
void Method1();
int Method2();
static SimpleRefPtr New() {
return TfCreateRefPtr(new Simple);
}
private:
Simple();
};
SimpleRefPtr p1; // p1 points to NULL
SimpleRefPtr p2 = Simple::New(); // p2 points to new object A
SimpleRefPtr p3 = Simple::New(); // p3 points to new object B
p1->Method1(); // runtime error -- p1 is NULL
p3 = p2; // object B is deleted
p2->Method1(); // Method1 on object A
int value = p3->Method2(); // Method2 on object A
p2.Reset(); // only p3 still points at A
p3 = p1; // object A is deleted
if (...) {
SimpleRefPtr p4 = Simple::New(); // p4 points to object C
p4->Method1();
} // object C destroyed

Note that Simple's constructor is private; this ensures that one can only get at a Simple through Simple::New(), which is careful to return a SimpleRefPtr.

Note that it is often useful to have both const and non-const versions of TfRefPtr for the same data type. Our convention is to use a typedef for each of these, with the const version beginning with "Const", after any prefix. The const version can be used as a parameter to a function in which you want to prevent changes to the pointed-to object. For example:

typedef TfRefPtr<XySimple> XySimpleRefPtr;
typedef TfRefPtr<const XySimple> XyConstSimpleRefPtr;
void
Func1(const XySimpleRefPtr &p)
{
p->Modify(); // OK even if Modify() is not a const member
}
void
Func2(const XyConstSimpleRefPtr &p)
{
p->Query(); // OK only if Query() is a const member
}

It is always possible to assign a non-const pointer to a const pointer variable. In extremely rare cases where you want to do the opposite, you can use the TfConst_cast function, as in:

XyConstSimpleRefPtr p1;
XySimpleRefPtr p2;
p1 = p2; // OK
p2 = p1; // Illegal!
p2 = TfConst_cast<XySimpleRefPtr>(p1); // OK, but discouraged

Comparisons and Tests

Reference-counted pointers of like type can be compared; any TfRefPtr can be tested to see it is NULL or not:

TfRefPtr<Elf> elf = Elf::New();
sneezy = Dwarf::New();
if (!sleepy)
... // true: sleepy is NULL
if (sneezy)
... // true: sneezy is non-nULL
bool b1 = (sleepy != sneezy),
b2 = (sleepy == sneezy),
b3 = (elf == sneezy); // compilation error -- type clash

Opaqueness

A TfRefPtr can be used as an opaque pointer, just as a regular pointer can. For example, without having included the header file for a class XySimple, the following will still compile:

class XySimple;
class Complicated {
public:
void SetSimple(const TfRefPtr<XySimple>& s) {
_simplePtr = s;
}
TfRefPtr<XySimple> GetSimple() {
return _simplePtr;
}
void Forget() {
_simplePtr.Reset();
}
private:
TfRefPtr<XySimple> _simplePtr;
};

Note that the call Forget() (or SetSimple() for that matter) may implicitly cause destruction of an XySimple object, if the count of the object pointed to by _simplePtr drops to zero. Even though the definition of XySimple is unknown, this compiles and works correctly.

The only time that the definition of XySimple is required is when putting a raw XySimple* into a TfRefPtr<XySimple>; note however, that this should in fact only be done within the class definition of XySimple itself.

Other cases that require a definition of XySimple are parallel to regular raw pointers, such as calling a member function, static or dynamic casts (but not const casts) and using the TfTypeid function. Transferring a TfWeakPtr to a TfRefPtr also requires knowing the definition of XySimple.

Sometimes a class may have many typedefs associated with it, having to do with TfRefPtr or TfWeakPtr. If it is useful to use the class opaquely, we recommend creating a separate file as follows:

// file: proj/xy/simplePtrDefs.h
typedef TfRefPtr<class XySimple> XySimpleRefPtr;
typedef TfRefPtr<const class XySimple> XyConstSimpleRefPtr;
// typedefs for TfWeakPtr<XySimple> would follow,
// if XySimple derives from TfWeakBase

The definition for XySimple would then use the typedefs:

#include "Proj/Xy/SimpleRefPtrDefs.h"
class XySimple : public TfRefBase {
public:
static XySimpleRefPtr New();
...
};

The above pattern now allows a consumer of class XySimple the option to include only simplePtrDefs.h, if using the type opaquely suffices, or to include simple.h, if the class definition is required.

Cyclic Dependencies

If you build a tree using TfRefPtr, and you only have pointers from parent to child, everything is fine: if you "lose" the root of the tree, the tree will correctly destroy itself.

But what if children point back to parents? Then a simple parent/child pair is stable, because the parent and child point at each other, and even if nobody else has a pointer to the parent, the reference count of the two nodes remains at one.

The solution to this is to make one of the links (typically from child back to parent) use a TfWeakPtr. If a class T is enabled for both "guarding" (see TfWeakBase) and reference counting, then a TfRefPtr can be converted to a TfWeakPtr (in this context, a "back pointer") and vice versa.

Inheritance

Reference-counted pointers obey the same rules with respect to inheritance as regular pointers. In particular, if class Derived is derived from class Base, then the following are legal:

TfRefPtr<Base> bPtr = new Base;
TfRefPtr<Derived> dPtr = new Derived;
TfRefPtr<Base> b2Ptr = dPtr; // initialization
b2Ptr = dPtr; // assignment
b2Ptr == dPtr; // comparison
dPtr = bPtr; // Not legal: compilation error

As the last example shows, initialization or assignment to a TfRefPtr<Derived> from a TfRefPtr<Base> is illegal, just as it is illegal to assign a Base* to a Derived*. However, if Derived and Base are polymorphic (i.e. have virtual functions) then the analogue of a dynamic_cast<> is possible:

Just like a regular dynamic_cast<> operation, the TfRefPtr returned by TfDynamic_cast<> points to NULL if the conversion fails, so that the operator can also be used to check types:

// complain: ptr is not of type T2

Similarly, one can use the TfStatic_cast<> operator to statically convert TfRefPtrs:

This is faster, but not as safe as using TfDynamic_cast.

Finally, remember that in C++, a Derived** is not a Base**, nor is a Derived*& a Base*&. This implies that

TfRefPtr<Base>* bPtrPtr = &dPtr; // compilation error
TfRefPtr<Base>& bPtrRef = dPtr; // compilation error
const TfRefPtr<Base>&bPtrRef = dPtr; // OK

The last initialization is legal because the compiler implicitly converts dPtr into a temporary variable of type TfRefPtr<Base>.

Thread Safety

One more comment about thread-safety: the above examples are thread-safe in the sense that if two or more threads create and destroy their own TfRefPtr objects, the reference counts of the underlying objects are always correct; said another way, the reference count it a thread-safe quantity.

However, it is never safe for two threads to simultaneously try to alter the same TfRefPtr object, nor can two threads safely call methods on the same underlying object unless that object itself guarantees thread safety.

Tracking References

The TfRefPtrTracker singleton can track TfRefPtr objects that point to particular instances. The macros TF_DECLARE_REFBASE_TRACK and TF_DEFINE_REFBASE_TRACK are used to enable tracking. Tracking is enabled at compile time but which instances to track is chosen at runtime.

Total Encapsulation If you're using TfRefPtrs on a type T, you probably want to completely forbid clients from creating their own objects of type T, and force them to go through TfRefPtrs. Such encapsulation is strongly encouraged. Here is the recommended technique:

typedef TfRefPtr<class Simple> SimpleRefPtr;
class Simple : public TfRefBase {
private: // use protected if you plan to derive later
Simple();
Simple(<arg-list>);
public:
static SimpleRefPtr New() {
return TfCreateRefPtr(new Simple);
}
static SimpleRefPtr New(<arg-list>) {
return TfCreateRefPtr(new Simple(<arg-list>));
}
~Simple();
};

Clients can now only create objects of type Simple using a TfRefPtr:

Simple s; // compilation error
SimpleRefPtr sPtr1 = new Simple; // compilation error
SimpleRefPtr sPtr2 = Simple::New(); // OK
SimpleRefPtr sPtr3 = Simple::New(<arg-list>); // Ok

Definition in file refPtr.h.

Macro Definition Documentation

#define TF_SUPPORTS_REFPTR (   T)    std::is_base_of_v<TfRefBase, T>

Definition at line 1367 of file refPtr.h.

Function Documentation

template<class T >
PXR_NAMESPACE_OPEN_SCOPE size_t hash_value ( const TfRefPtr< T > &  ptr)
inline

Definition at line 1353 of file refPtr.h.

template<class T >
bool operator!= ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1167 of file refPtr.h.

template<class T >
bool operator!= ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1172 of file refPtr.h.

template<class T >
bool operator< ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1178 of file refPtr.h.

template<class T >
bool operator< ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1183 of file refPtr.h.

template<class T >
bool operator<= ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1189 of file refPtr.h.

template<class T >
bool operator<= ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1194 of file refPtr.h.

template<class T >
bool operator== ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1156 of file refPtr.h.

template<class T >
bool operator== ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1161 of file refPtr.h.

template<class T >
bool operator> ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1200 of file refPtr.h.

template<class T >
bool operator> ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1205 of file refPtr.h.

template<class T >
bool operator>= ( const TfRefPtr< T > &  p,
std::nullptr_t   
)
inline

Definition at line 1211 of file refPtr.h.

template<class T >
bool operator>= ( std::nullptr_t  ,
const TfRefPtr< T > &  p 
)
inline

Definition at line 1216 of file refPtr.h.

template<class T >
void swap ( TfRefPtr< T > &  lhs,
TfRefPtr< T > &  rhs 
)
inline

Definition at line 1330 of file refPtr.h.

TF_API void Tf_PostNullSmartPtrDereferenceFatalError ( const TfCallContext ,
const char *   
)
void Tf_RefPtrTracker_Assign ( const void ,
const void ,
const void  
)
inline

Definition at line 472 of file refPtr.h.

void Tf_RefPtrTracker_Delete ( const void ,
const void  
)
inline

Definition at line 471 of file refPtr.h.

void Tf_RefPtrTracker_FirstRef ( const void ,
const void  
)
inline

Definition at line 468 of file refPtr.h.

void Tf_RefPtrTracker_LastRef ( const void ,
const void  
)
inline

Definition at line 469 of file refPtr.h.

void Tf_RefPtrTracker_New ( const void ,
const void  
)
inline

Definition at line 470 of file refPtr.h.

template<class T >
TfRefPtr<typename T::DataType> TfConst_cast ( const TfRefPtr< const typename T::DataType > &  ptr)
inline

Definition at line 1267 of file refPtr.h.

template<typename T >
TfRefPtr<T> TfCreateRefPtr ( T *  ptr)
inline

Definition at line 1223 of file refPtr.h.

template<class D , class T >
TfRefPtr<typename D::DataType> TfDynamic_cast ( const TfRefPtr< T > &  ptr)
inline

Definition at line 1240 of file refPtr.h.

template<class HashState , class T >
void TfHashAppend ( HashState &  h,
const TfRefPtr< T > &  ptr 
)
inline

Definition at line 1360 of file refPtr.h.

template<class D , class T >
TfRefPtr<typename D::DataType> TfSafeDynamic_cast ( const TfRefPtr< T > &  ptr)
inline

Definition at line 1249 of file refPtr.h.

template<class D , class T >
TfRefPtr<typename D::DataType> TfStatic_cast ( const TfRefPtr< T > &  ptr)
inline

Definition at line 1258 of file refPtr.h.

template<class T >
const std::type_info& TfTypeid ( const TfRefPtr< T > &  ptr)

Definition at line 1229 of file refPtr.h.