Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement Poco::SharedPtr using std::shared_ptr #1993

Merged
merged 1 commit into from
Nov 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 62 additions & 156 deletions Foundation/include/Poco/SharedPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,147 +20,67 @@

#include "Poco/Foundation.h"
#include "Poco/Exception.h"
#include "Poco/AtomicCounter.h"
#include <memory>
#include <algorithm>


namespace Poco {


class ReferenceCounter
/// Simple ReferenceCounter object, does not delete itself when count reaches 0.
{
public:
ReferenceCounter(): _cnt(1)
{
}

void duplicate()
{
++_cnt;
}

int release()
{
return --_cnt;
}

int referenceCount() const
{
return _cnt.value();
}

private:
AtomicCounter _cnt;
};


//@ deprecated
template <class C>
class ReleasePolicy
/// The default release policy for SharedPtr, which
/// simply uses the delete operator to delete an object.
{
public:
static void release(C* pObj)
/// Delete the object.
/// Note that pObj can be 0.
{
delete pObj;
}
};


template <class C>
class ReleaseArrayPolicy
/// The release policy for SharedPtr holding arrays.
class SharedPtr
/// As of POCO C++ Libraries Release 2.0, SharedPtr is a small wrapper around
/// std::shared_ptr, providing basic backwards compatibility to the 1.x SharedPtr
/// implementation.
///
/// Note: ReleasePolicy is no longer supported.
///
/// SharedPtr will be removed in a future release. New code should use
/// std::shared_ptr and existing code should be changed to use std::shared_ptr
/// instead of Poco::SharedPtr.
{
public:
static void release(C* pObj)
/// Delete the object.
/// Note that pObj can be 0.
SharedPtr()
{
delete [] pObj;
}
};


template <class C, class RC = ReferenceCounter, class RP = ReleasePolicy<C> >
class SharedPtr
/// SharedPtr is a "smart" pointer for classes implementing
/// reference counting based garbage collection.
/// SharedPtr is thus similar to AutoPtr. Unlike the
/// AutoPtr template, which can only be used with
/// classes that support reference counting, SharedPtr
/// can be used with any class. For this to work, a
/// SharedPtr manages a reference count for the object
/// it manages.
///
/// SharedPtr works in the following way:
/// If an SharedPtr is assigned an ordinary pointer to
/// an object (via the constructor or the assignment operator),
/// it takes ownership of the object and the object's reference
/// count is initialized to one.
/// If the SharedPtr is assigned another SharedPtr, the
/// object's reference count is incremented by one.
/// The destructor of SharedPtr decrements the object's
/// reference count by one and deletes the object if the
/// reference count reaches zero.
/// SharedPtr supports dereferencing with both the ->
/// and the * operator. An attempt to dereference a null
/// SharedPtr results in a NullPointerException being thrown.
/// SharedPtr also implements all relational operators and
/// a cast operator in case dynamic casting of the encapsulated data types
/// is required.
{
public:
SharedPtr(): _pCounter(new RC), _ptr(0)
SharedPtr(C* ptr):
_ptr(ptr)
{
}

SharedPtr(C* ptr)
try:
_pCounter(new RC),
SharedPtr(const std::shared_ptr<C>& ptr):
_ptr(ptr)
{
}
catch (...)

template <class Other>
SharedPtr(const SharedPtr<Other>& ptr):
_ptr(std::dynamic_pointer_cast<C>(ptr.shared_ptr()))
{
RP::release(ptr);
}

template <class Other, class OtherRP>
SharedPtr(const SharedPtr<Other, RC, OtherRP>& ptr): _pCounter(ptr._pCounter), _ptr(const_cast<Other*>(ptr.get()))
SharedPtr(const SharedPtr& ptr):
_ptr(ptr._ptr)
{
_pCounter->duplicate();
}

SharedPtr(const SharedPtr& ptr): _pCounter(ptr._pCounter), _ptr(ptr._ptr)
SharedPtr(SharedPtr&& ptr):
_ptr(std::move(ptr._ptr))
{
_pCounter->duplicate();
}

~SharedPtr()
{
try
{
release();
}
catch (...)
{
poco_unexpected();
}
}

SharedPtr& assign(C* ptr)
{
if (get() != ptr)
{
SharedPtr tmp(ptr);
swap(tmp);
}
_ptr.reset(ptr);
return *this;
}

SharedPtr& assign(const SharedPtr& ptr)
{
if (&ptr != this)
Expand All @@ -170,9 +90,9 @@ class SharedPtr
}
return *this;
}
template <class Other, class OtherRP>
SharedPtr& assign(const SharedPtr<Other, RC, OtherRP>& ptr)

template <class Other>
SharedPtr& assign(const SharedPtr<Other>& ptr)
{
if (ptr.get() != _ptr)
{
Expand All @@ -192,43 +112,53 @@ class SharedPtr
return assign(ptr);
}

template <class Other, class OtherRP>
SharedPtr& operator = (const SharedPtr<Other, RC, OtherRP>& ptr)
template <class Other>
SharedPtr& operator = (const SharedPtr<Other>& ptr)
{
return assign<Other>(ptr);
}

void swap(SharedPtr& ptr)
{
std::swap(_ptr, ptr._ptr);
std::swap(_pCounter, ptr._pCounter);
}

template <class Other>
SharedPtr<Other, RC, RP> cast() const
SharedPtr<Other> cast() const
/// Casts the SharedPtr via a dynamic cast to the given type.
/// Returns an SharedPtr containing NULL if the cast fails.
/// Example: (assume class Sub: public Super)
/// SharedPtr<Super> super(new Sub());
/// SharedPtr<Sub> sub = super.cast<Sub>();
/// poco_assert (sub.get());
{
Other* pOther = dynamic_cast<Other*>(_ptr);
if (pOther)
return SharedPtr<Other, RC, RP>(_pCounter, pOther);
return SharedPtr<Other, RC, RP>();
return SharedPtr(std::dynamic_pointer_cast<Other>(_ptr));
}

template <class Other>
SharedPtr<Other, RC, RP> unsafeCast() const
SharedPtr<Other> unsafeCast() const
/// Casts the SharedPtr via a static cast to the given type.
/// Example: (assume class Sub: public Super)
/// SharedPtr<Super> super(new Sub());
/// SharedPtr<Sub> sub = super.unsafeCast<Sub>();
/// poco_assert (sub.get());
{
Other* pOther = static_cast<Other*>(_ptr);
return SharedPtr<Other, RC, RP>(_pCounter, pOther);
return SharedPtr(std::static_pointer_cast<Other>(_ptr));
}

operator std::shared_ptr<C>()
{
return _ptr;
}

const std::shared_ptr<C>& shared_ptr() const
{
return _ptr;
}

std::shared_ptr<C>& shared_ptr()
{
return _ptr;
}

C* operator -> ()
Expand All @@ -253,22 +183,22 @@ class SharedPtr

C* get()
{
return _ptr;
return _ptr.get();
}

const C* get() const
{
return _ptr;
return _ptr.get();
}

operator C* ()
{
return _ptr;
return _ptr.get();
}

operator const C* () const
{
return _ptr;
return _ptr.get();
}

bool operator ! () const
Expand Down Expand Up @@ -370,10 +300,10 @@ class SharedPtr
{
return get() >= ptr;
}
int referenceCount() const

long referenceCount() const
{
return _pCounter->referenceCount();
return _ptr.use_count();
}

protected:
Expand All @@ -382,40 +312,16 @@ class SharedPtr
if (!_ptr)
throw NullPointerException();

return _ptr;
}

void release()
{
poco_assert_dbg (_pCounter);
int i = _pCounter->release();
if (i == 0)
{
RP::release(_ptr);
_ptr = 0;

delete _pCounter;
_pCounter = 0;
}
}

SharedPtr(RC* pCounter, C* ptr): _pCounter(pCounter), _ptr(ptr)
/// for cast operation
{
poco_assert_dbg (_pCounter);
_pCounter->duplicate();
return _ptr.get();
}

protected:
RC* _pCounter;
C* _ptr;

template <class OtherC, class OtherRC, class OtherRP> friend class SharedPtr;
std::shared_ptr<C> _ptr;
};


template <class C, class RC, class RP>
inline void swap(SharedPtr<C, RC, RP>& p1, SharedPtr<C, RC, RP>& p2)
template <class C>
inline void swap(SharedPtr<C>& p1, SharedPtr<C>& p2)
{
p1.swap(p2);
}
Expand Down
Loading