Files
pvData/src/misc/pv/sharedPtr.h
Michael Davidsaver c590204cf9 add epics::auto_ptr<T> and epics::swap()
Avoid the flood of auto_ptr deprecation warnings
in the common cases of using auto_ptr
to automatically delete.
2017-11-06 12:30:40 -06:00

228 lines
5.8 KiB
C++

/*
* Copyright information and license terms for this software can be
* found in the file LICENSE that is included with the distribution
*/
/**
* @author Michael Davidsaver
*/
#ifndef SHAREDPTR_H
#define SHAREDPTR_H
#include <memory> /* for auto_ptr */
/** @file sharedPtr.h
* Pulls in the std::tr1 namespace with the following names
*
* class shared_ptr
* class weak_ptr
* class bad_weak_ptr
* function static_pointer_cast;
* function dynamic_pointer_cast
* function const_pointer_cast
* function swap
* function get_deleter
* function enable_shared_from_this
*/
/* where should we look? (In decending order of preference)
*
* # manual (per source file) selection
* # c++11 version of <memory>, then alias into tr1
* # <tr1/memory>
* # boost version of tr1/memory
*/
/* Debugging shared_ptr with debugPtr.h requires >= c++11
*
* Define DEBUG_SHARED_PTR globally to cause epics::debug::shared_ptr
* to be injected as std::tr1::shared_ptr and the macro
* HAVE_SHOW_REFS will be defined.
*
* epics::debug::shared_ptr wraps std::shared_ptr with additional
* tracking of backwards references.
* std::shared_ptr::use_count() gives the number of shared_ptr
* (strong refs) to the referenced object.
*
* If use_count()==5 then epics::debug::shared_ptr::show_refs() will print
* 5 lines of the format
*
* # <addr>: <IP0> <IP1> ...
*
* Given the numberic address of each shared_ptr as well as the call stack
* at the point where it was initialized.
* Use the 'addr2line' utility to interpret the stack addresses.
*
* On linux w/ ASLR it is necessary to turn on static linking to meaningfully
* interpret call stack addresses.
* Append "STATIC_BUILD=YES" to configure/CONFIG_SITE
*/
//#define DEBUG_SHARED_PTR
#if defined(SHARED_FROM_MANUAL)
// define SHARED_FROM_MANUAL if from some reason it is desirable to manually select
// which shared_ptr implementation to use
#elif __cplusplus>=201103L || (defined(_MSC_VER) && (_MSC_VER>=1600)) || (__clang__ && __APPLE__)
// c++11 or MSVC 2010
// clang on linux has tr1/memory, clang on OSX doesn't
# define SHARED_FROM_STD
#elif defined(__GNUC__) && __GNUC__>=4 && !defined(vxWorks)
// GCC >=4.0.0
# define SHARED_FROM_TR1
#elif defined(_MSC_VER) && (_MSC_VER>1500 || defined(_HAS_TR1))
// MSVC > 2008, or 2008 w/ SP1
# define SHARED_FROM_TR1
#else
# define SHARED_FROM_BOOST
#endif
// go and get it
#if defined(SHARED_FROM_MANUAL)
// no-op
#elif defined(SHARED_FROM_STD)
#include <memory>
#ifndef DEBUG_SHARED_PTR
namespace std {
namespace tr1 {
using ::std::shared_ptr;
using ::std::weak_ptr;
using ::std::static_pointer_cast;
using ::std::dynamic_pointer_cast;
using ::std::const_pointer_cast;
using ::std::enable_shared_from_this;
using ::std::bad_weak_ptr;
}
}
#else // DEBUG_SHARED_PTR
#include "debugPtr.h"
namespace std {
namespace tr1 {
using ::epics::debug::shared_ptr;
using ::epics::debug::weak_ptr;
using ::epics::debug::static_pointer_cast;
using ::epics::debug::dynamic_pointer_cast;
using ::epics::debug::const_pointer_cast;
using ::epics::debug::enable_shared_from_this;
using ::std::bad_weak_ptr;
}
}
#endif // DEBUG_SHARED_PTR
#elif defined(SHARED_FROM_TR1)
# include <tr1/memory>
#elif defined(SHARED_FROM_BOOST)
#if defined(__GNUC__) && __GNUC__ < 3
#define BOOST_EXCEPTION_DISABLE
#define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
#endif
# include <boost/tr1/memory.hpp>
#else
# error No shared_ptr selection
#endif
// cleanup
#ifdef SHARED_FROM_STD
# undef SHARED_FROM_STD
#endif
#ifdef SHARED_FROM_TR1
# undef SHARED_FROM_TR1
#endif
#ifdef SHARED_FROM_BOOST
# undef SHARED_FROM_BOOST
#endif
namespace detail {
template<typename T>
struct ref_shower {
const std::tr1::shared_ptr<T>& ptr;
bool self, weak;
ref_shower(const std::tr1::shared_ptr<T>& ptr, bool self, bool weak) :ptr(ptr),self(self),weak(weak) {}
};
}
/** Print a list (one per line) of shared_ptr which refer to the same object
*
* @param ptr Use the object pointed to by this shared_ptr
* @param self include or omit a line for this shared_ptr
* @param weak include a line for each weak_ptr (not implemented)
@code
shared_ptr<int> x;
std::cout << show_referrers(x);
@endcode
*/
template<typename T>
inline ::detail::ref_shower<T> show_referrers(const std::tr1::shared_ptr<T>& ptr, bool self=true, bool weak=false)
{
return ::detail::ref_shower<T>(ptr, self, weak);
}
namespace std{
template<typename T>
inline std::ostream& operator<<(std::ostream& strm, const ::detail::ref_shower<T>& refs)
{
#ifdef HAVE_SHOW_REFS
refs.ptr.show_refs(strm, refs.self, refs.weak);
#endif // HAVE_SHOW_REFS
return strm;
}
}//namespace std
#define POINTER_DEFINITIONS(clazz) \
typedef std::tr1::shared_ptr<clazz> shared_pointer; \
typedef std::tr1::shared_ptr<const clazz> const_shared_pointer; \
typedef std::tr1::weak_ptr<clazz> weak_pointer; \
typedef std::tr1::weak_ptr<const clazz> const_weak_pointer
/* A semi-hack to help with migration from std::auto_ptr to std::unique_ptr,
* and avoid copious deprecation warning spam
* which may be hiding legitimate issues.
*
* Provides epics::auto_ptr<T> and epics::swap()
*
* epics::auto_ptr<T> is std::auto_ptr<T> for c++98
* and std::unique_ptr<T> for >= c++11.
*
* epics::swap() is the only supported operation.
* copy/assignment/return are not supported
* (use auto_ptr or unique_ptr explicitly).
*/
namespace epics{
#if __cplusplus>=201103L
template<typename T>
using auto_ptr = std::unique_ptr<T>;
template<typename T>
static inline void swap(auto_ptr<T>& lhs, auto_ptr<T>& rhs) {
lhs.swap(rhs);
}
#else
using std::auto_ptr;
template<typename T>
static inline void swap(auto_ptr<T>& lhs, auto_ptr<T>& rhs) {
auto_ptr<T> temp(lhs);
lhs = rhs;
rhs = temp;
}
#endif
}
#endif // SHAREDPTR_H