31

The std::shared_ptr constructor isn't behaving as I expected:

#include <iostream>
#include <vector>

void func(std::vector<std::string> strings)
{
    for (auto const& string : strings)
    {
        std::cout << string << '\n';
    }
}

struct Func
{
    Func(std::vector<std::string> strings)
    {
        for (auto& string : strings)
        {
            std::cout << string << '\n';
        }
    }
};

int main(int argc, const char * argv[])
{

    func({"foo", "bar", "baz"});
    Func({"foo", "bar", "baz"});
    //auto ptr = std::make_shared<Func>({"foo", "bar", "baz"}); // won't compile.
    //auto ptr = std::make_shared<Func>{"foo", "bar", "baz"}; // nor this.
    return 0;
}

Am I doing something wrong or is the compiler? The compiler is:

$ clang++ --version Apple clang version 4.0 (tags/Apple/clang-421.0.57) (based on LLVM 3.1svn)

edit: shared_ptr instead of make_shared.

Here's the error:

make -k 
clang++ -std=c++11 -stdlib=libc++    main.cc   -o main
main.cc:28:18: error: no matching function for call to 'make_shared'
      auto ptr = std::make_shared<Func>({"foo", "bar", "baz"});
                 ^~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/c++/v1/memory:4621:1: note: candidate function not viable:
     requires 0 arguments, but 1 was provided
make_shared(_Args&& ...__args)
^
1 error generated.

3 Answers 3

37

Try this:

auto ptr = std::make_shared<Func>(std::initializer_list<std::string>{"foo", "bar", "baz"});

Clang is not willing to deduce the type of {"foo", "bar", "baz"}. I'm currently not sure whether that is the way the language is supposed to work, or if we're looking at a compiler bug.

Sign up to request clarification or add additional context in comments.

3 Comments

Last I heard, it's known that perfect forwarding is not actually perfect at all when initializer lists are concerned.
{"foo", "bar", "baz"} is not an expression and as such has no type (except when used with auto).. Although it would be nice
{"foo", "bar", "baz"} can be array of std::string, char [][], wchar_t [][].... Compiler must know exactly what it needs to create.
6

The constructor of shared_ptr<T> takes a pointer of type T* as its argument, assumed to point to a dynamically allocated resource (or at least something that can be freed by the deleter). On the other hand, make_shared does the construction for you and takes the constructor arguments directly.

So either you say this:

std::shared_ptr<Foo> p(new Foo('a', true, Blue));

Or, much better and more efficiently:

auto p = std::make_shared<Foo>('a', true, Blue);

The latter form takes care of the allocation and construction for you, and in the process creates a more efficient implementation.

You could of course also say make_shared<Foo>(Foo('a', true, Blue)), but that would just create an unnecessary copy (which may be elided), and more importantly it creates needless redundancy. [Edit] For initializing your vector, this may be the best method:

auto p = std::make_shared<Func>(std::vector<std::string>({"a", "b", "c"}));

The important point is, though, that make_shared performs the dynamic allocation for you, while the shared-ptr constructor does not, and instead takes ownership.

2 Comments

"but that would just create an unnecessary copy" An unnecessary move.
@ildjarn: Well, that all depends, doesn't it? Anyway, "move" is just an optimized copy :-)
3

You need to use make_shared if you want to create a new object, constructed from those arguments, pointed to by a shared_ptr. shared_ptr<T> is like a pointer to T- it needs to be constructed with a pointer to T, not a T.

Edit: Perfect forwarding is in fact not at all perfect when initializer lists are involved (which is the suck). It's not a bug in the compiler. You will have to create an rvalue of type Func manually.

1 Comment

Sorry, the problem was with make_shared. I changed it to shared_ptr whilst futzing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.