std::Vector, SmartPointer and const_cast

T

Tobias Kilian

Hi Ng !

I wrote a SmartPointer class which holds a doubled linked list to all its
copies to ensure that all copies are holding the same pointer, even if
one copy changes later.
If the last SmartPointer in the list is destructed it deletes the
underlying pointer. Well at least it seemed worth trying, because i then
could make a vector of SmartPointers.
Now I wanted to make a vector<SmartPointer<someType> >. The problem is
that vector::push_back wants a const T& as argument, which i cannot
provide, because the Copy-Constructor changes the source Object (to
maintain the double linked list).

I think about providing a const copy-constructor (like the one i have
already) and doing a const_cast in it, but this does not seem to be a
good solution.
Is it safe ? I mean the source should be a valid Object at the time, the
copy-Constructor is called, doesn't it ?
Can anyone give me a hint on how to do it, and correct errors I might
have overseen in this implementation of SmartPointer ?:

Thanks a lot,
Tobias Kilian

template<typename Type> class SmartPointer
{
public:
/// \brief Default Constructor
SmartPointer() : mPointer(0), mNextCopy(0), mPrevCopy(0)
{ };

explicit SmartPointer(Type* pointer) : mPointer(pointer), mNextCopy
(0), mPrevCopy(0)
{
};

/// \brief Copy Constructor
SmartPointer( SmartPointer& source)
:mPointer(source.mPointer)
{
if (!source.mNextCopy)
{
mPrevCopy = &source;
mNextCopy = 0;
source.mNextCopy = this;
}
else
{
debugPrintAll();
mPrevCopy = &source;
mNextCopy = source.mNextCopy;
source.mNextCopy = this;
assert(mNextCopy);
mNextCopy->mPrevCopy = this;
}
}

/// \brief Copy Constructor in Question
SmartPointer( const SmartPointer& src)
:mPointer(src.mPointer)
{
SmartPointer& source = const_cast<SmartPointer&>(src);
if (!source.mNextCopy)
{
mPrevCopy = &source;
mNextCopy = 0;
source.mNextCopy = this;
}
else
{
mPrevCopy = &source;
mNextCopy = source.mNextCopy;
source.mNextCopy = this;
mNextCopy->mPrevCopy = this;
}
}


/// \brief Assignement operator
SmartPointer& SmartPointer::eek:perator= (SmartPointer& source)
{
if (mPointer != source.mPointer)
{
// First of all, delete the old pointer.
delete mPointer;

// Propagate pointer to previous copies
if (mPrevCopy!=0)
{
// rekursiv !
mPrevCopy->assignToPrev(source.mPointer);
}

// The new pointer is taken.
mPointer = source.mPointer;

// Propagate pointer to next copies
if (mNextCopy!=0)
{
mNextCopy->assignToNext(source.mPointer);
}

// Join the lists of this and of the source SmartPointer.
SmartPointer* lastCopy = getLastCopy();
SmartPointer* firstCopy = source.getFirstCopy();
lastCopy->mNextCopy = firstCopy;
firstCopy->mPrevCopy = lastCopy;
}
return *this;
}

SmartPointer* getFirstCopy()
{
if (mPrevCopy)
{
return mPrevCopy->getFirstCopy();
}
else
{
return this;
}
}

SmartPointer* getLastCopy()
{
if (mNextCopy)
{
return mNextCopy->getLastCopy();
}
else
{
return this;
}
}

/// \brief Destructor
~SmartPointer()
{
if (mPrevCopy==0 && mNextCopy==0)
{
delete mPointer;
}
else
{
if (mPrevCopy)
{
mPrevCopy->mNextCopy = mNextCopy;
}

if (mNextCopy)
{
mNextCopy->mPrevCopy = mPrevCopy;
}
}
};


Type* operator->() const { assert(mPointer); return mPointer;}
Type& operator* () const { assert(mPointer); return *mPointer;}

operator bool() const
{
return mPointer!=0;
}


protected:

void SmartPointer::assignToPrev(Type* pointer)
{
// take the given pointer...
mPointer = pointer;

// and progpagate it to the previous copies
if (mPrevCopy)
{
// rekursiv !
(*mPrevCopy).assignToPrev(pointer);
}
}

void SmartPointer::assignToNext(Type* pointer)
{
// take the given pointer...
mPointer = pointer;
if (mNextCopy) // is there another Next copy ?
{
// rekursiv !
(*mNextCopy).assignToNext(pointer);
}
}

Type* mPointer;
SmartPointer* mPrevCopy;
SmartPointer* mNextCopy;
};
 
T

tom_usenet

Hi Ng !

I wrote a SmartPointer class which holds a doubled linked list to all its
copies to ensure that all copies are holding the same pointer, even if
one copy changes later.
If the last SmartPointer in the list is destructed it deletes the
underlying pointer. Well at least it seemed worth trying, because i then
could make a vector of SmartPointers.

Sounds like a reference-linked smart pointer to me.
Now I wanted to make a vector<SmartPointer<someType> >. The problem is
that vector::push_back wants a const T& as argument, which i cannot
provide, because the Copy-Constructor changes the source Object (to
maintain the double linked list).

Your copy constructor should take a const T& - remember you can modify
pointed-to values in a const object. e.g.

explicit SmartPointer(Type* pointer)
: mPointer(pointer), mNextCopy(this), mPrevCopy(this)
{
//note next and prev point to this
};

/// \brief Copy Constructor
SmartPointer( SmartPointer const& source)
:mPointer(source.mPointer)
{
//cunning trick:
SmartPointer* nonConstSource = source.mPrev->mNext;
//...
}
I think about providing a const copy-constructor (like the one i have
already) and doing a const_cast in it, but this does not seem to be a
good solution.

You can avoid the const_cast as above. And note that reference linked
smart pointers can be less efficient than reference counted ones in
some circumstances, and that they are unsuitable for using from
multiple threads (unless you add some draconian locking to the class).

Tom
 
M

Michiel Salters

Tobias Kilian said:
Hi Ng !

I wrote a SmartPointer class which holds a doubled linked list to all its
copies to ensure that all copies are holding the same pointer, even if
one copy changes later.
If the last SmartPointer in the list is destructed it deletes the
underlying pointer. Well at least it seemed worth trying, because i then
could make a vector of SmartPointers.
Now I wanted to make a vector<SmartPointer<someType> >. The problem is
that vector::push_back wants a const T& as argument, which i cannot
provide, because the Copy-Constructor changes the source Object (to
maintain the double linked list).

Technically, yes. Logically, no. The solution is to make the link
pointers mutable. It is legal to change mutable members, even in const
objects. This way, your copy ctor can again take a const&.

Regards,
Michiel Salters
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top