2013-03-14 2 views
1

Я читаю Safe C++ и у меня есть вопрос о подсчете ссылок. Вопрос указан в разделе комментариев в коде ниже?Смысл подсчета ссылок указателей в C++

#include <iostream> 

using namespace std; 

template <typename T>class RefCountPtr { 
public: 
    explicit RefCountPtr(T* p = NULL) { 
      Create(p);  
    } 

    RefCountPtr(const RefCountPtr<T>& rhs) { 
     Copy(rhs);  
    } 

    RefCountPtr<T>& operator=(const RefCountPtr<T>& rhs) { 
     if(ptr_ != rhs.ptr_) { 
      Kill();   
      Copy(rhs); 
     } 
     return *this; 
    } 

    RefCountPtr<T>& operator=(T* p) { 
     if(ptr_ != p) { 
      Kill();  
      Create(p); 
     } 
     return *this; 
    } 
    ~RefCountPtr() { 
     Kill(); 
    } 
    T* Get() const { 
     return ptr_; 
    } 

    T* operator->() const { 
     // SCPP_TEST_ASSERT(ptr_ != NULL, "Attempt to use operator -> on NULL pointer."); 
     return ptr_;  
    } 

    T& operator*() const { 
     // SCPP_TEST_ASSERT(ptr_ != NULL, "Attempt to use operator * on NULL pointer."); 
     return *ptr_; 
    } 

    int GetCount() { return *count_; } 
private:  
    T* ptr_; 
    int* count_; 

    void Create(T* p) { 
     ptr_ = p; 
     if(ptr_ != NULL) { 
      count_ = new int; 
      *count_ = 1;  
     } else { 
      count_ = NULL; 
     } 
    } 

    void Copy(const RefCountPtr<T>& rhs) { 
     ptr_ = rhs.ptr_; 
     count_ = rhs.count_; 
     if(count_ != NULL) 
      ++(*count_); 
    } 

    void Kill() { 
     if(count_ != NULL) { 
      if(--(*count_) == 0) { 
       delete ptr_;  
       delete count_; 
      } 
     } 
    } 
}; 

void main() 
{ 

    int* pFirstInt = new int; 

    RefCountPtr<int> refPointer(pFirstInt); 

    cout << "count: " << refPointer.GetCount() << std::endl; 

    RefCountPtr<int> refSecondPointer = refPointer; // this calls copy constructor. 

    cout << "second count: " << refSecondPointer.GetCount() << std::endl; 

    RefCountPtr<int> refThirdPointer; 
    refThirdPointer = pFirstInt; **// Question why are we not incrementing same int pointer? How can we correct this? 
           // If we are not incrementing same pointer why author has provided 
           // operator = for data type T? 
           // Note: As expected program is crashing while exiting as we are deleting int pointer twice.** 

    std::cout << "Third pointer: " << refThirdPointer.GetCount() << std::endl; 

    RefCountPtr<int> refFourthPointer; 
    refFourthPointer = refSecondPointer; 

    cout << "Fourth count: " << refFourthPointer.GetCount() << std::endl; 

    return; 
} 

/* 
count: 1 
second count: 2 
Third pointer: 1 
Fourth count: 3 
Press any key to continue . . . 

*/ 
+1

Ugh. Причина в том, что нет 'std :: shared_ptr :: operator = (T *)'. – Zeta

+0

Вы не должны делать этого: 'int * pFirstInt = new int; RefCountPtr refPointer (pFirstInt) '. Сделайте 'RefCountPtr refPointer = новый int' вместо. –

+0

@ meh, когда я использовал RefCountPtr refPointer = new int Я получаю ошибку компиляции, не могу преобразовать из 'int *' в 'RefCountPtr ' – venkysmarty

ответ

3

Проблема заключается в том, что следующий:

refThirdPointer = pFirstInt; 

является назначением из исходного указателя, который управляет другим смарт-указателем.

Таким образом, вы получаете два несвязанных умных указателя, пытающихся управлять pFirstInt. Они не связаны между собой тем, что у них есть свои отдельные подсчеты и блаженно не знают о существовании друг друга. Это приводит к двойному удалению, которое вы наблюдаете.

+0

@ NPE Это значит, что я должен удалить RefCountPtr & operator = (T * p) в определении класса, чтобы избежать этого. Я не понимаю, почему автор предоставил тогда? – venkysmarty

+0

@venkysmarty: Я думаю, это опасно. Поэтому я лично либо удалю его, либо назову его чем-то другим (например, 'reset()', чтобы имитировать 'std :: shared_ptr'). – NPE

Смежные вопросы