SharedPtrControlBlock
template <typename T> class shared_ptr;
template <typename T> class weak_ptr;
// This class is an internal implementation detail for shared_ptr.
class SharedPtrControlBlock {
template <typename T> friend class shared_ptr;
template <typename T> friend class weak_ptr;
private:
SharedPtrControlBlock() : refcount_(1), weak_count_(1) { }
int refcount_;
int weak_count_;
};
// NOTE: It is strongly encouraged to use scoped_ptr if you could.
// shared_ptr should be only used at the cases that
// there is no clear owner for the object, anyone reference the object
// may need take care if the object should be deleted.
// NOTE: Don't use this class to replace boost::shared_ptr when working with
// thrift.
template <typename T>
class shared_ptr {
template <typename U> friend class weak_ptr;
public:
typedef T element_type;
explicit shared_ptr(T* ptr = NULL)
: ptr_(ptr),
control_block_(ptr != NULL ? new SharedPtrControlBlock : NULL) {
}
// Copy constructor: makes this object a copy of ptr
template <typename U>
shared_ptr(const shared_ptr<U>& ptr) // NOLINT
: ptr_(NULL),
control_block_(NULL) {
Initialize(ptr);
}
// Need non-templated version to prevent the compiler-generated default
shared_ptr(const shared_ptr<T>& ptr) // NOLINT
: ptr_(NULL),
control_block_(NULL) {
Initialize(ptr);
}
// Assignment operator. Replaces the existing shared_ptr with ptr.
template <typename U>
shared_ptr<T>& operator=(const shared_ptr<U>& ptr) {
if (ptr_ != ptr.ptr_) {
shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
swap(me);
}
return *this;
}
// Need non-templated version to prevent the compiler-generated default
shared_ptr<T>& operator=(const shared_ptr<T>& ptr) {
if (ptr_ != ptr.ptr_) {
shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
swap(me);
}
return *this;
}
~shared_ptr() {
if (ptr_ != NULL) {
if (AtomicDecrement(&control_block_->refcount_) == 0) {
delete ptr_;
// weak_count_ is defined as the number of weak_ptrs that observe
// ptr_, plus 1 if refcount_ is nonzero.
if (AtomicDecrement(&control_block_->weak_count_) == 0) {
delete control_block_;
}
}
}
}
// Replaces underlying raw pointer with the one passed in. The reference
// count is set to one (or zero if the pointer is NULL) for the pointer
// being passed in and decremented for the one being replaced.
void reset(T* p = NULL) {
if (p != ptr_) {
shared_ptr<T> tmp(p);
tmp.swap(*this);
}
}
// Exchanges the contents of this with the contents of r. This function
// supports more efficient swapping since it eliminates the need for a
// temporary shared_ptr object.
void swap(shared_ptr<T>& r) {
std::swap(ptr_, r.ptr_);
std::swap(control_block_, r.control_block_);
}
// The following function is useful for gaining access to the underlying
// pointer when a shared_ptr remains in scope so the reference-count is
// known to be > 0 (e.g. for parameter passing).
T* get() const {
return ptr_;
}
T& operator*() const {
return *ptr_;
}
T* operator->() const {
return ptr_;
}
int use_count() const {
return control_block_ ? control_block_->refcount_ : 1;
}
bool unique() const {
return use_count() == 1;
}
private:
// If r is non-empty, initialize *this to share ownership with r,
// increasing the underlying reference count.
// If r is empty, *this remains empty.
// Requires: this is empty, namely this->ptr_ == NULL.
template <typename U>
void Initialize(const shared_ptr<U>& r) {
if (r.control_block_ != NULL) {
AtomicIncrement(&r.control_block_->refcount_);
ptr_ = r.ptr_;
control_block_ = r.control_block_;
}
}
T* ptr_;
SharedPtrControlBlock* control_block_;
template <typename U>
friend class shared_ptr;
};
// Matches the interface of std::swap as an aid to generic programming.
template <typename T> void swap(shared_ptr<T>& r, shared_ptr<T>& s) {
r.swap(s);
}
// Weak ptrs:
// The weak_ptr auxiliary class is used to break ownership cycles. A weak_ptr
// points to an object that's owned by a shared_ptr, but the weak_ptr is an
// observer, not an owner. When the last shared_ptr that points to the object
// disappear, the weak_ptr expires, at which point the expired() member
// function will return true.
// You can't directly get a raw pointer from weak_ptr, to access a weak_ptr's
// pointed-to object, use lock() to obtain a temporary shared_ptr.
// See the draft C++ standard (as of October 2007 the latest draft is N2461)
// for the detailed specification.
template <typename T>
class weak_ptr {
template <typename U> friend class weak_ptr;
public:
typedef T element_type;
// Create an empty (i.e. already expired) weak_ptr.
weak_ptr() : ptr_(NULL), control_block_(NULL) { }
// Create a weak_ptr that observes the same object that ptr points
// to. Note that there is no race condition here: we know that the
// control block can't disappear while we're looking at it because
// it is owned by at least one shared_ptr, ptr.
template <typename U> weak_ptr(const shared_ptr<U>& ptr) {
CopyFrom(ptr.ptr_, ptr.control_block_);
}
// Copy a weak_ptr. The object it points to might disappear, but we
// don't care: we're only working with the control block, and it can't
// disappear while we're looking at because it's owned by at least one
// weak_ptr, ptr.
template <typename U> weak_ptr(const weak_ptr<U>& ptr) {
CopyFrom(ptr.ptr_, ptr.control_block_);
}
// Need non-templated version to prevent default copy constructor
weak_ptr(const weak_ptr& ptr) {
CopyFrom(ptr.ptr_, ptr.control_block_);
}
// Destroy the weak_ptr. If no shared_ptr owns the control block, and if
// we are the last weak_ptr to own it, then it can be deleted. Note that
// weak_count_ is defined as the number of weak_ptrs sharing this control
// block, plus 1 if there are any shared_ptrs. We therefore know that it's
// safe to delete the control block when weak_count_ reaches 0, without
// having to perform any additional tests.
~weak_ptr() {
if (control_block_ != NULL &&
(AtomicDecrement(&control_block_->weak_count_) == 0)) {
delete control_block_;
}
}
weak_ptr& operator=(const weak_ptr& ptr) {
if (&ptr != this) {
weak_ptr tmp(ptr);
tmp.swap(*this);
}
return *this;
}
template <typename U> weak_ptr& operator=(const weak_ptr<U>& ptr) {
weak_ptr tmp(ptr);
tmp.swap(*this);
return *this;
}
template <typename U> weak_ptr& operator=(const shared_ptr<U>& ptr) {
weak_ptr tmp(ptr);
tmp.swap(*this);
return *this;
}
void swap(weak_ptr& ptr) {
swap_weak_ptr(ptr_, ptr.ptr_);
swap_weak_ptr(control_block_, ptr.control_block_);
}
void reset() {
weak_ptr tmp;
tmp.swap(*this);
}
// Return the number of shared_ptrs that own the object we are observing.
// Note that this number can be 0 (if this pointer has expired).
int use_count() const {
return control_block_ != NULL ? control_block_->refcount_ : 0;
}
bool expired() const { return use_count() == 0; }
private:
void CopyFrom(T* ptr, SharedPtrControlBlock* control_block) {
ptr_ = ptr;
control_block_ = control_block;
if (control_block_ != NULL)
AtomicIncrement(&control_block_->weak_count_);
}
private:
element_type* ptr_;
SharedPtrControlBlock* control_block_;
};
template <typename T> void swap_weak_ptr(weak_ptr<T>& r, weak_ptr<T>& s) {
r.swap(s);
}