1

I am reading Safe C++ and I have question on reference counting. Question is provided in comment section in code below?

#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 . . .

*/
5
  • 2
    Ugh. There's a reason for no std::shared_ptr::operator=(T*). Commented Mar 14, 2013 at 11:19
  • You should not do this: int* pFirstInt = new int; RefCountPtr<int> refPointer(pFirstInt). Do RefCountPtr<int> refPointer = new int instead. Commented Mar 14, 2013 at 11:21
  • @ meh when I used RefCountPtr<int> refPointer = new int I am getting compilation error cannot convert from 'int *' to 'RefCountPtr<T>' Commented Mar 14, 2013 at 11:25
  • @venkysmarty - because the constructor is explicit? Commented Mar 14, 2013 at 11:26
  • @Zeta What reason is that? The lack of implicit conversions from shared_ptr to raw pointers (and viceversa) is exactly the reason why I don't like the standard smart pointers. Commented Mar 14, 2013 at 13:13

1 Answer 1

2

The problem is that the following:

refThirdPointer = pFirstInt;

is assigning from a raw pointer that's already managed by another smart pointer.

Thus you end up having two unrelated smart pointers trying to manage pFirstInt. They are unrelated in that they have their separate reference counts, and are blissfully unaware of each other's existence. This leads to the double delete that you're observing.

Sign up to request clarification or add additional context in comments.

2 Comments

@ NPE Is that mean I should remove RefCountPtr<T>& operator=(T* p) in class definition to avoid this. I am not getting why author has provided then?
@venkysmarty: I think it's dangerous. Therefore, I personally would either remove it, or call it something else (e.g. reset() to mimic std::shared_ptr).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.