0

My abstract Reference counter class:

template<class T>
class ReferenceCounter
{
public:

    ReferenceCounter();
    ~ReferenceCounter();

    void addRef();
    void release();

    uint32 getCountReferences() const;

protected:
    int32* pCountReferences;

    virtual void destroyObject() = 0;
    virtual void shallowCopy(const T& rhs) = 0;
};

template<class T>
inline ReferenceCounter<T>::ReferenceCounter() 
{
    pCountReferences = new int32;
    *pCountReferences = 1;
}

template<class T>
inline ReferenceCounter<T>::~ReferenceCounter() 
{
    if(pCountReferences != NULL && *pCountReferences == 0)
    {
        delete pCountReferences;
        pCountReferences = NULL;
    }
}

template<class T>
inline void ReferenceCounter<T>::addRef()
{
    debug_assert((*pCountReferences) >= 0, "Incorrect value of count references");
    ++(*pCountReferences);
}

template<class T>
inline void ReferenceCounter<T>::release()
{
    debug_assert((*pCountReferences) > 0, "Incorrect value of count references");
    (*pCountReferences)--;

    if(pCountReferences != NULL && *pCountReferences == 0)
    {
        destroyObject();
    }
}

template<class T>
inline uint32 ReferenceCounter<T>::getCountReferences() const
{
    return *pCountReferences;
}

This is my smart pointer :

template<class T>
class SmartPtr
{
public:
    SmartPtr();
    SmartPtr(T* pInst);
    SmartPtr(const SmartPtr<T>& rhs);
    ~SmartPtr();

    void operator = (const SmartPtr<T>& rhs);
    T* operator -> () const;
    T* getData() const;

    bool isNULL() const;

private:
    T* pInst;
};

template<class T>
SmartPtr<T>::SmartPtr() : pInst(NULL) {}

template<class T>
SmartPtr<T>::SmartPtr(T* pInst) : pInst(pInst) {}

template<class T>
SmartPtr<T>::~SmartPtr() 
{
    if(pInst != NULL)
    {
        pInst->release();
    }
}

template<class T>
SmartPtr<T>::SmartPtr(const SmartPtr<T>& rhs)
{
    this->pInst = rhs.pInst;
    if(pInst != NULL)
    {
        pInst->addRef();
    }
}

template<class T>
void SmartPtr<T>::operator= (const SmartPtr<T>& rhs)
{
    this->pInst = rhs.pInst;
    if(pInst != NULL)
    {
        pInst->addRef();
    }
}

template<class T>
T* SmartPtr<T>::operator->() const
{
    return pInst;
}

template<class T>
T* SmartPtr<T>::getData() const
{
    return pInst;
}

template<class T>
bool SmartPtr<T>::isNULL() const
{
    return pInst == NULL;
}

There are test of code :

#include <iostream>
#include "ReferenceCounter.h"
#include "SmartPtr.h"

using namespace std;

class B;

class A : public ReferenceCounter<A>
{
public:
    A();
    A(const A& rhs);
    ~A();

    SmartPtr<B> getB();
    void operator = (const A& rhs);

    private:
    void destroyObject();
    void shallowCopy(const A& rhs);
 };

class B : public ReferenceCounter<B>
{
private:
    void destroyObject() {} ;
    void shallowCopy(const B& rhs) {};
};

A::A()
{
    cout << "Create object" << endl;
}

A::A(const A& rhs)
{
    shallowCopy(rhs);
    addRef();
    cout << "copy constructor " << endl;
}

A::~A()
{
    release();
}

void A::destroyObject()
{
    cout << "destroy" << endl;
}

void A::shallowCopy(const A& rhs)
{
    this->pCountReferences = rhs.pCountReferences;
}

void A::operator = (const A& rhs)
{
    shallowCopy(rhs);
    addRef();
    cout << "operator = " << endl;
}

SmartPtr<B> A::getB()
{
    return SmartPtr<B>(new B());
}

SmartPtr<A> getA()
{
    SmartPtr<A> a(new A());
    return a;
}

int main()
{
    getA();
    return 0;
}

This code is worked but below not called copy constructor of smart pointer when i debug this code . What problems happens below ??

int main()
{
   A a;
   a.getB();
}
Dzmitry93
  • 13
  • 2

1 Answers1

0

See here for Return value optimization.

The compiler is allowed, to eliminate the copy of a temporary object being returned.

With C++11, there's also the possibility of moving an object. See What are move semantics? for an explanation.

Update:

This is not a problem at all, just a compiler optimization.

As long as there's nothing special going on in your constructor and destructor, there's no need to prevent this optimization. You should allow this instead, because it makes your program run faster by skipping one constructor and one destructor call.

Community
  • 1
  • 1
Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198
  • I asked about it before and get advice make SmartPtr(new B()) as volatile but than i have error " SmartPtr has no suitable copy constructor " – Dzmitry93 Jan 05 '13 at 21:56
  • @Dzmitry93 What do you mean with "make as volatile"? Can you show the modified code in your question? – Olaf Dietsche Jan 05 '13 at 22:02
  • Advice : "declaring returned the smart pointer object volatile will prevent RVO from applying"; code : SmartPtr A::getB() { return volatile SmartPtr(new B()); } – Dzmitry93 Jan 05 '13 at 22:10
  • @Dzmitry93 Ok, I haven't seen this kind of use `volatile`. I just tested this and it doesn't work. What works is `return (volatile SmartPtr) SmartPtr(new B());`, but this needs a copy constructor like `SmartPtr(volatile SmartPtr)`. – Olaf Dietsche Jan 05 '13 at 22:50
  • So, problem is solved when i write that code 'SmartPtr A::getB() { SmartPtr b(new B()); return b; }' instead 'SmartPtr A::getB() { return SmartPtr(new B()); }' . Was the problem in RVO then ? – Dzmitry93 Jan 05 '13 at 23:02