Search code examples
c++stlargumentssingly-linked-list

STL List Insert asks for 3 arguments


Working with an STL list today. First time using one, and I'm not terribly familiar with the member functions, and I'm not sure I fully understand iterators. Non-the-less, I have done the research, and cannot seem to understand why the insert function from the STL list is demanding I pass it 3 arguments

note:   candidate expects 3 arguments, 2 provided
Houses.insert(it,temp);

here is a segement of my code. Just for reference, this bit appears multiple times throughout, and the error crops up at every instance.

temp = new WolfDen;
it = Houses.begin();
Houses.insert(it,temp);
temp -> setDimensions();

Houses is my STL list of "homes". WolfDen is a derived class of homes. temp is homes pointer, and it is my list iterator.


Solution

  • Assumptions

    Based on the comments Houses is probably defined as

    std::list<Home> Houses;
    

    and WolfDen inherits from Home;

    class WolfDen : public Home
    

    Store Polymorphic Objects

    Since you probably intend to use the whole WolfDen object, you need to store the pointer:

    std::list<Home *> Houses;
    

    or in modern C++ (since C++11):

    std::list<std::unique_ptr<Home>> Houses;
    

    If you use the bare pointer variant std::list<Home *>, be sure to delete the objects pointed to, once you are done with them. E.g. right before leaving the scope in which Houses is defined do

    for (std::list<Home *>::const_iterator homeIt  = Houses.begin(),
                                           homeEnd = Houses.end();
         homeIt != homeEnd; ++homeIt)
    {
        delete *homeIt;
    }
    

    Store By-Value

    If you stay with your definition as std::list<Home>, the following insert statement will compile:

    Houses.insert(it,*temp);
    

    But this would insert another Home object into Houses which is a copy only of the Home part of the WolfDen object *temp stored at the location pointed to by temp. (The new object will be Houses.front())

    The subsequent modification

    temp->setDimensions();
    

    will only modify the original object *temp and not Houses.front(). Also, the object *temp will probably leak, unless you add

    delete temp;
    

    at the end of your code.

    However, it is much better, not to use pointers at all:

    Home temp;
    temp.setDimensions();
    it = Houses.begin();
    Houses.insert(it,temp);
    

    (Note, that class WolfDen is not used, since only the Home part will be used anyway.)

    Understanding the error message

    note:   candidate expects 3 arguments, 2 provided
    

    To understand this, have a look at http://en.cppreference.com/w/cpp/container/list/insert: The version you intend to call is version (1) of std::list::insert

    iterator insert( iterator pos, const T & value ); (1)
    

    where T is Home. I.e.

    iterator insert( iterator pos, const Home & value );
    

    For the parameter pos you provide an argument of type std::list<Home>::iterator, which is fine. But for the parameter value you provide an argument of type Home * (or possibly WolfDen * which converts to Home *), which is a pointer. Pointers do not convert to values (or references to values in this case) implicitly. The match with the version (1) therefore fails.

    However, pointers convert to integer types implicitly. Since there are other versions of std::list::insert, the compiler tries these, as well. The first two provided arguments match to version (3) in http://en.cppreference.com/w/cpp/container/list/insert:

    void insert( iterator pos, size_type count, const T & value ); (3)
    

    The pointer of type Home * converts to size_type. But then the third argument value is missing... Some compilers are more elaborate and list the possible candidates and also more information about the failed matches.

    If value would not be needed, you code might have compiled. Since pointers are usually converted to rather large values, your application would have added a rather large number of entries to Houses. (You can try this by changing your code to Houses.insert(it,temp, WolfDen());. But be prepared to run out of memory ;-)).