Forked from
Core Modules / dune-common
5655 commits behind the upstream repository.
-
Oliver Sander authored
[[Imported from SVN: r6810]]
Oliver Sander authored[[Imported from SVN: r6810]]
shared_ptr.hh 12.22 KiB
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// $Id: smartpointer.hh 5504 2009-04-08 13:35:31Z christi $
#ifndef DUNE_SHARED_PTR_HH
#define DUNE_SHARED_PTR_HH
#if defined SHARED_PTR_HEADER
# include SHARED_PTR_HEADER
#endif
#if defined HAVE_BOOST_SHARED_PTR_HPP
#if defined HAVE_BOOST_MAKE_SHARED_HPP
# include <boost/make_shared.hpp>
#endif
#endif
#include <dune/common/nullptr.hh>
#include <dune/common/typetraits.hh>
/**
* @file
* @brief This file implements the class shared_ptr (a reference counting
* pointer), for those systems that don't have it in the standard library.
* @author Markus Blatt
*/
namespace Dune
{
// A shared_ptr implementation has been found if SHARED_PTR_NAMESPACE is set at all
#ifdef SHARED_PTR_NAMESPACE
using SHARED_PTR_NAMESPACE :: shared_ptr;
#else
/** @addtogroup Common
*
* @{
*/
/**
* @brief A reference counting smart pointer.
*
* It is designed such that it is usable within a std::vector.
* The contained object is destroyed only if there are no more
* references to it.
*/
template<class T>
class shared_ptr
{
public:
/**
* @brief The data type we are a pointer for.
*
* This has to have a parameterless constructor.
*/
typedef T element_type;
/**
* @brief Constructs a new smart pointer and allocates the referenced Object.
*/
inline shared_ptr();
/**
* @brief Constructs a new smart pointer from a preallocated Object.
*
* \param pointer Raw pointer to the shared data
*
* note: the object must be allocated on the heap and after handing the pointer to
* shared_ptr the ownership of the pointer is also handed to the shared_ptr.
*/
inline shared_ptr(T * pointer);
/**
* @brief Constructs a new smart pointer from a preallocated Object.
*
* \tparam Deleter This class must by copyconstructable, the copy constructor must not throw an exception
* and it must implement void operator() (T*) const
*
* \param pointer Raw pointer to the shared data
* \param deleter A copy of this deleter is stored
*
* note: the object must be allocated on the heap and after handing the pointer to
* shared_ptr the ownership of the pointer is also handed to the shared_ptr.
*/
template<class Deleter>
inline shared_ptr(T * pointer, Deleter deleter);
/**
* @brief Copy constructor.
* @param pointer The object to copy.
*/
inline shared_ptr(const shared_ptr<T>& pointer);
/**
* @brief Destructor.
*/
inline ~shared_ptr();
/** \brief Assignment operator */
inline shared_ptr& operator=(const shared_ptr<T>& pointer);
/** \brief Dereference as object */
inline element_type& operator*();
/** \brief Dereference as pointer */
inline element_type* operator->();
/** \brief Dereference as const object */
inline const element_type& operator*() const;
/** \brief Dereference as const pointer */
inline const element_type* operator->() const;
/** \brief Access to the raw pointer, if you really want it */
element_type* get() const {
return rep_==0 ? 0 : rep_->rep_;
}
/** \brief Swap content of this shared_ptr and another */
inline void swap(shared_ptr& other);
/** \brief Decrease the reference count by one and free the memory if the
reference count has reached 0
*/
inline void reset();
/** \brief Detach shared pointer and set it anew for the given pointer */
inline void reset(T* pointer);
//** \brief Same as shared_ptr(pointer,deleter).swap(*this)
template<class Deleter>
inline void reset(T* pointer, Deleter deleter);
/** \brief The number of shared_ptrs pointing to the object we point to */
int use_count() const;
private:
/** @brief The object we reference. */
class PointerRep
{
friend class shared_ptr<element_type>;
protected:
/** @brief The number of references. */
int count_;
/** @brief The representative. */
element_type * rep_;
/** @brief Constructor from existing Pointer. */
PointerRep(element_type * p) : count_(1), rep_(p) {}
/** @brief Destructor, deletes element_type* rep_. */
virtual ~PointerRep() {};
};
/** @brief Adds call to deleter to PointerRep. */
template<class Deleter>
class PointerRepImpl :
public PointerRep
{
friend class shared_ptr<element_type>;
/** @brief Constructor from existing Pointer with custom deleter. */
PointerRepImpl(element_type * p, const Deleter& deleter) :
PointerRep(p),
deleter_(deleter)
{}
/** @brief Destructor, deletes element_type* rep_ using deleter. */
~PointerRepImpl()
{ deleter_(this->rep_); }
// store a copy of the deleter
Deleter deleter_;
};
/** \brief A default deleter that just calls delete */
struct DefaultDeleter
{
void operator() (element_type* p) const
{ delete p; }
};
PointerRep *rep_;
// Needed for the implicit conversion to "bool"
typedef T* shared_ptr::PointerRep::*__unspecified_bool_type;
public:
/** \brief Implicit conversion to "bool" */
operator __unspecified_bool_type() const // never throws
{
return rep_ == 0 ? 0 : &shared_ptr::PointerRep::rep_;
}
};
template<class T>
inline shared_ptr<T>::shared_ptr(T * p)
{
rep_ = new PointerRepImpl<DefaultDeleter>(p, DefaultDeleter());
}
template<class T>
template<class Deleter>
inline shared_ptr<T>::shared_ptr(T * p, Deleter deleter)
{
rep_ = new PointerRepImpl<Deleter>(p, deleter);
}
template<class T>
inline shared_ptr<T>::shared_ptr()
{
rep_ = nullptr;
}
template<class T>
inline shared_ptr<T>::shared_ptr(const shared_ptr<T>& other) : rep_(other.rep_)
{
if (rep_)
++(rep_->count_);
}
template<class T>
inline shared_ptr<T>& shared_ptr<T>::operator=(const shared_ptr<T>& other)
{
if (other.rep_)
(other.rep_->count_)++;
if(rep_!=0 && --(rep_->count_)<=0)
delete rep_;
rep_ = other.rep_;
return *this;
}
template<class T>
inline shared_ptr<T>::~shared_ptr()
{
if(rep_!=0 && --(rep_->count_)==0) {
delete rep_;
rep_=0;
}
}
template<class T>
inline T& shared_ptr<T>::operator*()
{
return *(rep_->rep_);
}
template<class T>
inline T *shared_ptr<T>::operator->()
{
return rep_->rep_;
}
template<class T>
inline const T& shared_ptr<T>::operator*() const
{
return *(rep_->rep_);
}
template<class T>
inline const T *shared_ptr<T>::operator->() const
{
return rep_->rep_;
}
template<class T>
inline int shared_ptr<T>::use_count() const
{
return rep_->count_;
}
template<class T>
inline void shared_ptr<T>::swap(shared_ptr<T>& other)
{
PointerRep* dummy = rep_;
rep_ = other.rep_;
other.rep_ = dummy;
}
template<class T>
inline void shared_ptr<T>::reset()
{
shared_ptr<T>().swap(*this);
}
template<class T>
inline void shared_ptr<T>::reset(T* pointer)
{
shared_ptr<T>(pointer).swap(*this);
}
template<class T>
template<class Deleter>
inline void shared_ptr<T>::reset(T* pointer, Deleter deleter)
{
shared_ptr<T>(pointer, deleter).swap(*this);
}
/** @} */
#endif // #ifdef SHARED_PTR_NAMESPACE
// C++0x and Boost have a make_shared implementation, TR1 does not.
// Unfortunately, TR1 gets picked over Boost if present.
// Moreover, boost::make_shared() only exists for (remotely) recent versions of Boost.
#if HAVE_MAKE_SHARED
#ifdef SHARED_PTR_NAMESPACE
using SHARED_PTR_NAMESPACE :: make_shared;
#endif
#else
template<typename T>
shared_ptr<T> make_shared()
{
return shared_ptr<T>(new T());
}
template<typename T, typename Arg1>
shared_ptr<T> make_shared(const Arg1& arg1)
{
return shared_ptr<T>(new T(arg1));
}
template<typename T, typename Arg1, typename Arg2>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2)
{
return shared_ptr<T>(new T(arg1,arg2));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
{
return shared_ptr<T>(new T(arg1,arg2,arg3));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4,
const Arg5& arg5)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4,arg5));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4,
const Arg5& arg5, const Arg6& arg6)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4,arg5,arg6));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4,
const Arg5& arg5, const Arg6& arg6, const Arg7& arg7)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4,arg5,arg6,arg7));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7, typename Arg8>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4,
const Arg5& arg5, const Arg6& arg6, const Arg7& arg7, const Arg8& arg8)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8));
}
template<typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4,
typename Arg5, typename Arg6, typename Arg7, typename Arg8, typename Arg9>
shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, const Arg4& arg4,
const Arg5& arg5, const Arg6& arg6, const Arg7& arg7, const Arg8& arg8,
const Arg9& arg9)
{
return shared_ptr<T>(new T(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9));
}
#endif // custom make_shared
/**
@brief implements the Deleter concept of shared_ptr without deleting anything
@relates shared_ptr
If you allocate an object on the stack, but want to pass it to a class or function as a shared_ptr,
you can use this deleter to avoid accidental deletion of the stack-allocated object.
For convenience we provide two free functions to create a shared_ptr from a stack-allocated object
(\see stackobject_to_shared_ptr):
1) Convert a stack-allocated object to a shared_ptr:
@code
int i = 10;
shared_ptr<int> pi = stackobject_to_shared_ptr(i);
@endcode
2) Convert a stack-allocated object to a shared_ptr of a base class
@code
class A {};
class B : public A {};
...
B b;
shared_ptr<A> pa = stackobject_to_shared_ptr<A>(b);
@endcode
@tparam T type of the stack-allocated object
*/
template<class T>
struct null_deleter
{
void operator() (T* p) const {}
};
/**
@brief Convert a stack-allocated object to a shared_ptr:
@relates shared_ptr
@code
int i = 10;
shared_ptr<int> pi = stackobject_to_shared_ptr(i);
@endcode
*/
template<typename T>
inline shared_ptr<T> stackobject_to_shared_ptr(T & t)
{
return shared_ptr<T>(&t, null_deleter<T>());
}
/**
@brief Convert a stack object to a shared_ptr of a base class
@relates shared_ptr
@code
class A {};
class B : public A {};
...
B b;
shared_ptr<A> pa = stackobject_to_shared_ptr<A>(b);
@endcode
*/
template<typename T, typename T2>
inline shared_ptr<T2> stackobject_to_shared_ptr(T & t)
{
return shared_ptr<T2>(dynamic_cast<T2*>(&t), null_deleter<T2>());
}
}
#endif