vendredi 19 août 2016

Compilation error when returning an std::map of implicitly non-copyable structs on new versions of gcc

I get this strange compilation error on new versions of gcc (4.9+).

Here is the code:

#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <map>

using namespace std;

struct ptrwrap
{
    unique_ptr<int> foo;
};

template <typename T>
struct holder
{
    holder() = default;

    holder(const holder& b)
        : t(b.t)
    {
    }

    holder(holder&& b)
        : t(std::move(b.t))
    {
    }

    holder& operator=(const holder& h)
    {
        t = h.t;
        return *this;
    }

    holder& operator=(holder&& h)
    {
        t = std::move(h.t);
        return *this;
    }

    T t;
};

struct y_u_no_elision
{
    holder<ptrwrap> elem;
};

typedef map<std::string, y_u_no_elision> mymap;

mymap foo();

int main()
{
    auto m = foo();
    m = foo();
    return 0;
}

Here it is on ideone too with the actual error. Basically it boils down to using the deleted copy constructor of ptrwrap. Which... shouldn't happen. The map is returned by value (ie moved), so no copies can exist.

Now the same code is compiled with no problems on older versions of gcc (I tried 4.2 and 4.3), all versions of clang I tried, and also Visual Studio 2015.

Curiously if I remove the explicit copy and move constructors of the holder template, it also compiles on gcc 4.9+. If I change the map to a vector or an unordered_map it also compiles fine (here is a link to a compiling version of the code with unordered_map)

So... is this a gcc 4.9 bug or are the other compilers being permissive of something I can't see? Is there anything I can do about this which doesn't involve changing the holder class?

Aucun commentaire:

Enregistrer un commentaire