std::Vector, SmartPointer and const_cast

Discussion in 'C++' started by Tobias Kilian, May 24, 2004.

  1. 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;
    };
     
    Tobias Kilian, May 24, 2004
    #1
    1. Advertising

  2. Tobias Kilian

    tom_usenet Guest

    On 24 May 2004 15:18:11 GMT, Tobias Kilian
    <> wrote:

    >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
    --
    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
     
    tom_usenet, May 24, 2004
    #2
    1. Advertising

  3. Tobias Kilian <> wrote in message news:<Xns94F3B005E951gunnaratuniminuskobl@141.26.64.5>...
    > 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
     
    Michiel Salters, May 25, 2004
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anonymous
    Replies:
    20
    Views:
    4,426
    Pete Becker
    Mar 30, 2005
  2. Jason Heyes
    Replies:
    8
    Views:
    766
    Andrew Koenig
    Jan 15, 2006
  3. Replies:
    8
    Views:
    1,996
    Csaba
    Feb 18, 2006
  4. Tom Smith
    Replies:
    5
    Views:
    854
    Tom Smith
    Oct 4, 2006
  5. Rune Allnor
    Replies:
    4
    Views:
    992
    Rune Allnor
    Dec 11, 2008
Loading...

Share This Page