基本的にあなたは正しいです。boost::enable_shared_from_this
あなたの例はダングリングポインターになります(基本クラスとして使用する場合、いくつかの例外があることに注意してください)。
説明
問題
boost:shared_ptr
同じアイデアをstd::shared_ptr
共有します。生のポインターからの参照カウントを使用してスマートポインターを作成します。ただし、すべてのスマート ポインターに共通の問題もあります。他のスマート ポインターに関連付けられていない別のスマート ポインターで生のポインターを使用すると、ダングリング ポインターと の複数回の呼び出しで終了しますdelete
。
int * ptr = new int;
{
std::shared_ptr<int> shared1(ptr); // initialise a new ref_count = 1
{
std::shared_ptr<int> shared2(ptr); // initialise a new ref_count = 1
} // first call of delete, since shared2.use_count() == 0
} // second call of delete, since shared1.use_count() == 0. ooops
"解決"
オブジェクトへS
の生のポインターから最初のスマート ポインターを作成した後は、 からの派生物でない限り、ではなく でのみコピー コンストラクターを使用する必要があります。ブーストにはこれと多少同等のものがありますが、生のポインターとスマートポインターを混在させることは依然として悪い考えです。さらに良い-スマートポインターを使用する場合は、生のポインターを使用しないでください。p
O
S
p
O
std::enable_shared_from_this
std::shared_ptr<int> ptr(new int);
{
std::shared_ptr<int> shared1(ptr); // ptr.use_count() == 2
{
std::shared_ptr<int> shared2(ptr); // ptr.use_count() = 3
} // ptr.use_count() = 2
} // ptr.use_count() = 1
さらに良いことに、メモリを自分で割り当てるのではなく、std::make_shared
orを使用しboost:make_shared
ます。
std::shared_ptr<int> ptr = std::make_shared<int>();
{
std::shared_ptr<int> shared1(ptr); // ptr.use_count() == 2
{
std::shared_ptr<int> shared2(ptr); // ptr.use_count() == 3
} // ptr.use_count() == 2
} // ptr.use_count() == 1
可能な実装
次の実装は、 と をサポートしstd::shared_ptr
ていないため、 に比べて非常に粗雑です。ただし、共有ポインターを処理する方法の概要を説明する必要があります。std::weak_ptr
std::enable_shared_from_this
//!\brief Base clase for reference counter
class reference_base{
reference_base(const reference_base&); // not copyable
reference_base& operator=(const reference_base &){return *this;}// not assignable
protected:
size_t ref_count; //!< reference counter
virtual void dispose() = 0; //!< pure virtual
public:
//! initialize with a single reference count
reference_base() : ref_count(1){}
//! returns the current count of references
size_t use_count() const{
return ref_count;
}
//! increases the current count of references
void increase(){
ref_count++;
}
//! decreases the current count of references and dispose if the counter drops to zero
void decrease(){
if(--ref_count == 0)
dispose();
}
};
//! \brief Specialized version for pointer
template <class T>
class reference_base_ptr : public reference_base{
typedef T* pointer_type;
protected:
//! uses delete to deallocate memory
virtual void dispose(){
delete ptr;
ptr = 0;
}
public:
reference_base_ptr(T * ptr) : ptr(ptr){}
pointer_type ptr;
};
//! \brief Specialized version for arrays
template <class T>
class reference_base_range : public reference_base{
typedef T* pointer_type;
protected:
virtual void dispose(){
delete[] ptr;
ptr = 0;
}
public:
reference_base_range(T * ptr) : ptr(ptr){}
pointer_type ptr;
};
/***********************************************************/
//! base class for shared memory
template <class T, class reference_base_type>
class shared_memory{
public:
typedef T element_type;
//! Standard constructor, points to null
shared_memory() : reference_counter(new reference_base_type(0)){}
//! Constructs the shared_memroy and creates a new reference_base
template<class Y> shared_memory(Y * ptr){
try{
reference_counter = new reference_base_type(ptr);
}catch(std::bad_alloc &e){
delete ptr;
throw;
}
}
//! Copies the shared_memory and increases the reference count
shared_memory(const shared_memory & o) throw() : reference_counter(o.reference_counter){
o.reference_counter->increase();
}
//! Copies the shared_memory of another pointer type and increases the reference count.
//! Needs the same reference_base_type
template<class Y>
shared_memory(const shared_memory<Y,reference_base_type> & o) throw() : reference_counter(o.reference_counter){
reference_counter->increase();
}
//! Destroys the shared_memory object and deletes the reference_counter if this was the last
//! reference.
~shared_memory(){
reference_counter->decrease();
if(reference_counter->use_count() == 0)
delete reference_counter;
}
//! Returns the number of references
size_t use_count() const{
return reference_counter->use_count();
}
//! Returns a pointer to the refered memory
T * get() const{
return reference_counter->ptr;
}
//! Checks whether this object is unique
bool unique() const{
return use_count() == 1;
}
//! Checks whehter this object is valid
operator bool() const{
return get() != 0;
}
//! Checks doesn't reference anythign
bool empty() const{
return get() == 0;
}
//! Assignment operator for derived classes
template<class Y>
shared_memory& operator=(const shared_memory<Y,reference_base_type> & o){
shared_memory<Y,reference_base_type> tmp(o);
swap(tmp);
}
//! Assignment operator
shared_memory& operator=(const shared_memory & o){
shared_memory tmp(o);
swap(tmp);
return *this;
}
/** resets the ptr to NULL. If this was the last shared_memory object
* owning the referenced object, the object gets deleted.
* \sa ~shared_memory
*/
void reset(){
shared_memory tmp;
swap(tmp);
}
/** releases the old object and takes a new one
*/
template <class Y>
void reset(Y * ptr){
shared_memory tmp(ptr);
swap(tmp);
}
/** swaps the owned objects of two shared_memory objects.
*/
void swap(shared_memory & r){
reference_base_type * tmp = reference_counter;
reference_counter = r.reference_counter;
r.reference_counter = tmp;
}
protected:
reference_base_type * reference_counter; //!< Actually reference counter and raw pointer
};
/***********************************************************/
//! ptr (single object) specialization
template <class T>
class shared_ptr : public shared_memory<T,reference_base_ptr<T> >{
typedef reference_base_ptr<T> reference_counter_type;
typedef shared_memory<T,reference_counter_type> super;
typedef T element_type;
public:
shared_ptr(){}
template<class Y> shared_ptr(Y * ptr){
try{
super::reference_counter = new reference_counter_type(ptr);
}catch(std::bad_alloc &e){
//couldn't allocated memory for reference counter
delete ptr; // prevent memory leak
throw bad_alloc();
}
}
element_type & operator*() const{
return *(super::reference_counter->ptr);
}
element_type * operator->() const{
return super::reference_counter->ptr;
}
};
/***********************************************************/
//! array (range) specialization
template <class T>
class shared_array : public shared_memory<T,reference_base_range<T> >{
typedef reference_base_range<T> reference_counter_type;
typedef shared_memory<T,reference_counter_type> super;
typedef T element_type;
public:
shared_array(){}
template<class Y> shared_array(Y * ptr){
try{
super::reference_counter = new reference_counter_type(ptr);
}catch(std::bad_alloc &e){
delete[] ptr;
throw bad_alloc();
}
}
element_type & operator[](int i) const{
return *(super::reference_counter->ptr + i);
}
};
以下も参照してください。