/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file pointerTo.h * @author drose * @date 1998-10-23 */ #ifndef POINTERTO_H #define POINTERTO_H /** * This file defines the classes PointerTo and ConstPointerTo (and their * abbreviations, PT and CPT). These should be used in place of traditional * C-style pointers wherever implicit reference counting is desired. * * The syntax is: instead of: * * PointerTo p; MyClass *p; * PT(MyClass) p; * * ConstPointerTo p; const MyClass *p; * CPT(MyClass) p; * * PointerTo and ConstPointerTo will automatically increment the object's * reference count while the pointer is kept. When the PointerTo object is * reassigned or goes out of scope, the reference count is automatically * decremented. If the reference count reaches zero, the object is freed. * * Note that const PointerTo is different from * ConstPointerTo. A const PointerTo may not reassign its pointer, * but it may still modify the contents at that address. On the other hand, a * ConstPointerTo may reassign its pointer at will, but may not modify the * contents. It is like the difference between (MyClass * const) and * (const MyClass *). * * In order to use PointerTo, it is necessary that the thing pointed to * --MyClass in the above example--either inherits from ReferenceCount, or is * a proxy built with RefCountProxy or RefCountObj (see referenceCount.h). * However, also see PointerToArray, which does not have this restriction. * * It is crucial that the PointerTo object is only used to refer to objects * allocated from the free store, for which delete is a sensible thing to do. * If you assign a PointerTo to an automatic variable (allocated from the * stack, for instance), bad things will certainly happen when the reference * count reaches zero and it tries to delete it. * * It's also important to remember that, as always, a virtual destructor is * required if you plan to support polymorphism. That is, if you define a * PointerTo to some base type, and assign to it instances of a class derived * from that base class, the base class must have a virtual destructor in * order to properly destruct the derived object when it is deleted. */ #include "pandabase.h" #include "pointerToBase.h" #include "register_type.h" /** * PointerTo is a template class which implements a smart pointer to an object * derived from ReferenceCount. */ template class PointerTo : public PointerToBase { public: typedef typename PointerToBase::To To; PUBLISHED: ALWAYS_INLINE constexpr PointerTo() noexcept = default; ALWAYS_INLINE explicit constexpr PointerTo(std::nullptr_t) noexcept {} ALWAYS_INLINE PointerTo(To *ptr) noexcept; INLINE PointerTo(const PointerTo ©); public: INLINE PointerTo(PointerTo &&from) noexcept; template ALWAYS_INLINE explicit PointerTo(Y *ptr) noexcept; template ALWAYS_INLINE PointerTo(const PointerTo &r) noexcept; template ALWAYS_INLINE PointerTo(PointerTo &&r) noexcept; INLINE PointerTo &operator = (PointerTo &&from) noexcept; template ALWAYS_INLINE PointerTo &operator = (const PointerTo &r) noexcept; template ALWAYS_INLINE PointerTo &operator = (PointerTo &&r) noexcept; constexpr To &operator *() const noexcept; constexpr To *operator -> () const noexcept; // MSVC.NET 2005 insists that we use T *, and not To *, here. constexpr operator T *() const noexcept; INLINE T *&cheat(); PUBLISHED: // When downcasting to a derived class from a PointerTo, C++ // would normally require you to cast twice: once to an actual BaseClass // pointer, and then again to your desired pointer. You can use the handy // function p() to avoid this first cast and make your code look a bit // cleaner. // e.g. instead of (MyType *)(BaseClass *)ptr, use (MyType *)ptr.p() // If your base class is a derivative of TypedObject, you might want to use // the DCAST macro defined in typedObject.h instead, e.g. DCAST(MyType, // ptr). This provides a clean downcast that doesn't require .p() or any // double-casting, and it can be run-time checked for correctness. constexpr To *p() const noexcept; INLINE PointerTo &operator = (To *ptr); INLINE PointerTo &operator = (const PointerTo ©); // These functions normally wouldn't need to be redefined here, but we do so // anyway just to help out interrogate (which doesn't seem to want to // automatically export the PointerToBase class). When this works again in // interrogate, we can remove these. #ifdef CPPPARSER INLINE bool is_null() const; INLINE void clear(); #endif }; /** * A ConstPointerTo is similar to a PointerTo, except it keeps a const pointer * to the thing. * * (Actually, it keeps a non-const pointer, because it must be allowed to * adjust the reference counts, and it must be able to delete it when the * reference count goes to zero. But it presents only a const pointer to the * outside world.) * * Notice that a PointerTo may be assigned to a ConstPointerTo, but a * ConstPointerTo may not be assigned to a PointerTo. */ template class ConstPointerTo : public PointerToBase { public: typedef typename PointerToBase::To To; PUBLISHED: ALWAYS_INLINE constexpr ConstPointerTo() noexcept = default; ALWAYS_INLINE explicit constexpr ConstPointerTo(std::nullptr_t) noexcept {} ALWAYS_INLINE ConstPointerTo(const To *ptr) noexcept; INLINE ConstPointerTo(const PointerTo ©); INLINE ConstPointerTo(const ConstPointerTo ©); public: INLINE ConstPointerTo(PointerTo &&from) noexcept; INLINE ConstPointerTo(ConstPointerTo &&from) noexcept; template ALWAYS_INLINE explicit ConstPointerTo(const Y *ptr) noexcept; template ALWAYS_INLINE ConstPointerTo(const PointerTo &r) noexcept; template ALWAYS_INLINE ConstPointerTo(const ConstPointerTo &r) noexcept; template ALWAYS_INLINE ConstPointerTo(PointerTo &&r) noexcept; template ALWAYS_INLINE ConstPointerTo(ConstPointerTo &&r) noexcept; INLINE ConstPointerTo &operator = (PointerTo &&from) noexcept; INLINE ConstPointerTo &operator = (ConstPointerTo &&from) noexcept; template ALWAYS_INLINE ConstPointerTo &operator = (const PointerTo &r) noexcept; template ALWAYS_INLINE ConstPointerTo &operator = (const ConstPointerTo &r) noexcept; template ALWAYS_INLINE ConstPointerTo &operator = (PointerTo &&r) noexcept; template ALWAYS_INLINE ConstPointerTo &operator = (ConstPointerTo &&r) noexcept; constexpr const To &operator *() const noexcept; constexpr const To *operator -> () const noexcept; constexpr operator const T *() const noexcept; INLINE const T *&cheat(); PUBLISHED: constexpr const To *p() const noexcept; INLINE ConstPointerTo &operator = (const To *ptr); INLINE ConstPointerTo &operator = (const PointerTo ©); INLINE ConstPointerTo &operator = (const ConstPointerTo ©); // This functions normally wouldn't need to be redefined here, but we do so // anyway just to help out interrogate (which doesn't seem to want to // automatically export the PointerToBase class). When this works again in // interrogate, we can remove this. #ifdef CPPPARSER INLINE void clear(); #endif }; // The existence of these functions makes it possible to sort vectors of // PointerTo objects without incurring the cost of unnecessary reference count // changes. The performance difference is dramatic! template void swap(PointerTo &one, PointerTo &two) noexcept { one.swap(two); } template void swap(ConstPointerTo &one, ConstPointerTo &two) noexcept { one.swap(two); } // Define owner_less specializations, for completeness' sake. namespace std { template struct owner_less > { bool operator () (const PointerTo &lhs, const PointerTo &rhs) const noexcept { return lhs < rhs; } }; template struct owner_less > { bool operator () (const ConstPointerTo &lhs, const ConstPointerTo &rhs) const noexcept { return lhs < rhs; } }; } // Finally, we'll define a couple of handy abbreviations to save on all that // wasted typing time. #define PT(type) PointerTo< type > #define CPT(type) ConstPointerTo< type > // Now that we have defined PointerTo, we can define what it means to take the // TypeHandle of a PointerTo object. template INLINE TypeHandle _get_type_handle(const PointerTo *) { return T::get_class_type(); } template INLINE TypeHandle _get_type_handle(const ConstPointerTo *) { return T::get_class_type(); } #include "pointerTo.I" #endif