mardi 21 juin 2016

Why does adding a destructor change the copy constructor behavior of this struct?


I have a bit of code that I find confusing. In particular, when I try to add something to a list as an initializer-list - it works until I add a destructor - then it starts trying to find a copy constructor.

This doesn't seem to be completely consistent behavior. Take this minimal example:

#include <list>
int main()
{
    class MemberType
    {
    public:
        MemberType()  {}
        MemberType(MemberType&& copy) { }
    };
    struct ListItemType
    {
        MemberType x;
        ~ListItemType() {}
    };
    std::list<ListItemType> myList;
    myList.push_back({MemberType()});
    return 0;
}

This fails to compile in GCC and VS2015 because the push_back attempts to access the ListItemType copy constructor main()::ListItemType::ListItemType(const main()::ListItemType&) (as per my understanding). This seems to make some sense as the list push_back will make a copy (since there is no move constructor), except this is NOT the behavior if you remove the destructor. Comment out the destructor and the compilation succeeds as expected.

That said, the following works fine even with the destructor - no copy or move constructors are needed to satisfy it. This seems like the same behavior to me though.

ListItemType foo = { MemberType() };

Finally, if you delete or comment out the move constructor of MemberType - the compilation again succeeds - meaning the following will compile.

#include <list>
int main()
{
    class MemberType
    {
    public:
        MemberType()  {}
    };
    struct ListItemType
    {
        MemberType x;
        ~ListItemType() {}
    };
    std::list<ListItemType> myList;
    myList.push_back({MemberType()});
    return 0;
}

Can someone please explain the behavior here? Why does the push_back try to access the copy constructor of ListItemType - but only if ListItemType has a destructor and MemberType has a move constructor?


Aucun commentaire:

Enregistrer un commentaire