Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::make_shared, std::unique_ptr and move constructors

Tags:

c++

c++11

stl

clang

The following code compiles with clang 3.0/libc++:

#include <memory>

class Foo
{
public:
    Foo()
        : mem_(new int(10))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>();
    return 0;
}

But this one doesn't (std::string parameter added):

#include <memory>
#include <string>

class Foo
{
public:
    Foo(const std::string& s)
        : mem_(new int(10))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>("aaa");
    return 0;
}

Clang complains about the usage of a deleted constructor. To me, this makes no sense, since std::make_shared isn't supposed to copy the Foo instance, the only thing that would trigger the call to the (deleted) copy constructor of std::unique_ptr.

But lo and behold, as soon as I define a move constructor explicitly, it compiles.

#include <memory>
#include <string>

class Foo
{
public:
    Foo(const std::string& s)
        : mem_(new int(10))
    {
    }
    Foo(Foo&& other)
        : mem_(std::move(other.mem_))
    {
    }
    std::unique_ptr<int> mem_;
};

int main()
{
    auto foo = std::make_shared<Foo>("aaa");
    return 0;
}

Now, questions:

  1. Why does it compile in the first example but not the second?
  2. Can std::make_shared copy/move the object while constructing it?
  3. Why does adding a move constructor fix the problem? I don't recall that adding non-default constructor should suppress an implicit move constructor.

EDIT: Checked and all examples appear to compile fine with gcc 4.5.1 (via ideone.com), I suspect it's the case of a clang/libc++ bug, but questions 2 and 3 still stand, plus I'd like to know which compiler is more "correct".

like image 248
Alex B Avatar asked Dec 19 '11 11:12

Alex B


1 Answers

Why does it compile in the first example but not the second?

This is a libc++ bug. I am working on a fix for it now...

Can std::make_shared copy/move the object while constructing it?

No, I don't believe it can.

Why does adding a move constructor fix the problem? I don't recall that adding non-default constructor should suppress an implicit move constructor.

In the version of clang you're using, implicit move constructors are not implemented yet.

Update

Fixed: http://llvm.org/bugs/show_bug.cgi?id=11616

like image 83
Howard Hinnant Avatar answered Oct 15 '22 14:10

Howard Hinnant