Search code examples
c++constantscopy-constructorauto-ptrtemporary-objects

How to allow non-const copy constructor for temporaries


How do I allow a class with a copy constructor that takes a non-const reference to be copy-constructed from temporaries?

The background is this:

I have a function that should return a list of pointers to objects that all inherit from Base, so I need something like vector<Base*>. Given that vector<auto_ptr> is not much of an option, I wanted to write a simple wrapper around vector<Base*> that deletes all elements in its destructor.

I'm facing the following problem:

My class has a copy constructor as follows:

auto_list(auto_list& rhs);

so that I can copy the pointer list to the new instance and clear it in the old one.

But obviously, that won't work with return values because temporaries don't bind to a non-const reference. Seeing that auto_ptr can be returned from functions, how did they implement it?

Note: I can't use C++11 or boost, so move semantics or unique_ptr are not an option.

If it helps, this is my code so far:

template <typename T> class auto_list
{
private:

    vector<T*> pointers;

public:

    auto_list(vector<T*>& pointers)
    {
        this->pointers = pointers;
    }

    auto_list(auto_list& rhs)
    {
        this->pointers = rhs.pointers;
        rhs.pointers.clear();
    }

    ~auto_list()
    {
        for(typename vector<T*>::const_iterator it = this->pointers.begin(); it != this->pointers.end(); it++)
        {
            delete (*it);
        }
    }

    auto_list& operator=(auto_list& rhs)
    {
        this->pointers = rhs.pointers;
        rhs.pointers.clear();
    }

    vector<T*> get_pointers() const
    {
        return this->pointers;
    }
};

Solution

  • This class will be rather confusing to use, just as auto_ptr itself, and I urge you to use more sensible smart pointers. Even if you do have a good reason for not using Boost (and for the life of me I can't think why not), how about std::tr1::shared_ptr?

    If you're determined to pursue this course, then auto_ptr solves the problem of initialising from a temporary by wrapping a reference in a class (auto_ptr_ref). The wrapper is created by a conversion function from *this (which is an lvalue, and therefore can be bound to a non-const reference), and can then be passed by value to a constructor.

    You can do something similar:

    template <typename T> class auto_list_ref
    {
        friend class auto_list<T>;
        auto_list_ref(auto_list<T> & ref) : ref(ref) {}
        auto_list<T> & ref;
    };
    
    template <typename T> class auto_list
    {
    public:
        // Add a constructor and conversion operator as follows:
    
        auto_list(auto_list_ref<T> rhs)
        {
            this->pointers = rhs.ref.pointers;
            rhs.ref.pointers.clear();
        }
    
        operator auto_list_ref<T>() {return auto_list_ref<T>(*this);}
    };
    

    Here is a demonstration.