IDDQD
IDDQD

Reputation: 3731

Reference counter for intrusive smart pointers

The following is a code excerpt written by a colleague that is no longer working with us. I have questions as to why this code was written in this way and not any other. My impression of the colleague is a very good one, he was one of the few people capable of compiling C++ code in his head.

#include <boost/smart_ptr.hpp>

namespace boost
{

/*****************************************
class RefCounter
{
protected:
    RefCounter() : m_refCount(0) {}
    virtual ~RefCounter() { }

private:
    friend void intrusive_ptr_release(RefCounter * p);
    friend void intrusive_ptr_add_ref(RefCounter * p);

    volatile long m_refCount;

    virtual void incRef() {__sync_add_and_fetch(&m_refCount, 1);}
    virtual void decRef() {if (__sync_sub_and_fetch(&m_refCount, 1) == 0) delete this;}
};

inline void intrusive_ptr_add_ref(RefCounter * p)
{
    p->incRef();
}

inline void intrusive_ptr_release(RefCounter * p)
{
    p->decRef();
}
************************************************/

class RefCounter
{
protected:
    RefCounter() : m_refCount(0) {}
    RefCounter(const RefCounter&) : m_refCount(0) {}
    virtual ~RefCounter() {}

    long getRefCount() const {return m_refCount;}

private:
    friend void intrusive_ptr_release(RefCounter * p);
    friend void intrusive_ptr_add_ref(RefCounter * p);
    volatile long m_refCount;
};

inline void intrusive_ptr_add_ref(RefCounter * p)
{
    __sync_add_and_fetch(&p->m_refCount, 1);
}

inline void intrusive_ptr_release(RefCounter * p)
{
    if (__sync_sub_and_fetch(&p->m_refCount, 1) == 0) delete p;
}

} // namespace boost

Example of use:

struct Foo : public boost::RefCounter
{
    int a;
};

typedef boost::intrusive_ptr<Foo> FooIntrusivePtr;
FooIntrusivePtr fooPtr;

My questions are the following:

  1. Why use friend keywords? Why not declare the functions public?

  2. Why use volative keyword? Where and why could the compiler aggressively optimize this value? Or was this keyword merely used as a precaution?

And as a bonus, why was the previous approach (commented out) replaced with the existing code? Was something wrong with the previous approach, a bug or special scenario which did not work as intended?

Much appreciated.

Upvotes: 1

Views: 281

Answers (1)

Kurt Stutsman
Kurt Stutsman

Reputation: 4034

The functions are marked friend so that they can edit the m_refCount member variable of the class even though it's private and the functions are not part of the class itself.

The volatile keyword as well as why it's using the __sync_ functions is to allow this implementation to work in a multi-threaded environment without using a mutex.

Upvotes: 3

Related Questions