Search code examples
c++overloadingcopy-constructorassignment-operator

Copy Constructor or overloading Operator= with an inherited list of pointers


I have a Class that inherit from a list of pointers, example:

Class C : protected list<Type*>

Now, i want to overload the operator= (and to write the copy constructor). Should i iterate the list making a new Type for each pointer inside the list?

void C::operator=(const C& c)
{
    if(!(*this)==c))
    {
        clear();
        for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
        {
           Type* cp = new Type((*it)); //or doing cp=&(*it) after the new
           push_back(cp);
        }
    }
}

or can i do this?

void C::operator=(const C& c)
{
    if(!(*this)==c))
    {
        clear();
        for(list<Type*>::iterator it = c.begin(); it != c.end(); it++)
        {
           Type* cp = it; //or cp=&(*it)
           push_back(cp);
        }
    }
}

Solution

  • I've edited my answer, as this is a homework exercise

    In a normal application you shouldn't derive from a STL container, their destructors are not virtual. Thus when C is destroyed, the std::list<T> will remain, causing a memory leak. They are not meant to be inherited form in the first place...

    In a normal design, you would have the list as an object:

    #include <list>
    
    template<typename T>
    class C {
    private:
        std::list<T*> lst;
    public:
        C& operator=(const C& c) {
            if (this != &c) {
                lst = c.lst;
            }
            return *this;
        }
    };
    

    What I would consider a GOOD exercise is that you implement a MyList class, making everything from scratch. But it is common knowledge that professors make student do weird illogical stuff. So lets assume you indeed want to derive from std::list and only overload operator=, doing the copy yourself

    #include <list>
    
    template<typename T> 
    class C : protected std::list<T*>
    {
    public:
        constexpr C& operator=(C const& c) noexcept {
            if (this != &c) {
                this->clear();
                // copy
            }
            return *this;
        }
    };
    

    Now, how do you copy... many flavors! There's the good-old C-style loop:

    for (int i = 0; i < c.size(); ++i) this->push_back(c[i]);
    

    There's the iterator loop:

    for (std::list<T*>::const_iterator it = c.cbegin(); it != c.cend(); ++it) this->push_back(*it);
    

    There's the iterator loop with auto and generalized accessors:

    for (auto it = std::cbegin(c); it != std::cend(c); ++it) this->push_back(*it);
    

    There's range-based for loops:

    for (auto const& el : c) this->push_back(el);
    

    There's algorithms, like std::for_each

    std::for_each(std::cbegin(c), std::cend(c), [this](T* ptr) { this->push_back(ptr); });
    

    ... and std::copy

    std::copy(std::cbegin(c), std::cend(c), std::back_inserter(*this));
    

    note that std::back_inserter is an iterator that performs a push_back while iterating.

    And in the future (C++20) we will have ranges, so you can write something like

    std::ranges::copy(c, *this);
    

    Although I'm not sure that's correct...

    Choose your poison!