Initializing container of unique_ptrs from initializer list fails with GCC 4.7
After "fixing" your example:
#include <vector>
#include <memory>
#include <string>
int main()
{
std::vector<std::unique_ptr<std::string>> vs = { { new std::string{"Doug"} }, { new std::string{"Adams"} } }; // fails
std::unique_ptr<std::string> ps { new std::string{"42"} }; // OK
}
I got very a clear error message:
error: converting to 'std::unique_ptr<std::basic_string<char> >' from initializer list would use explicit constructor 'std::unique_ptr<_Tp, _Dp>::unique_ptr(std::unique_ptr<_Tp, _Dp>::pointer) [with _Tp = std::basic_string<char>, _Dp = std::default_delete<std::basic_string<char> >, std::unique_ptr<_Tp, _Dp>::pointer = std::basic_string<char>*]'
This error tells us that it is not possible to use the unique_ptr
's explicit contructor!
unique_ptr
's constructor is explicit
. So you can't create one implicitly with from new string{"foo"}
. It needs to be something like unique_ptr<string>{ new string{"foo"} }
.
Which leads us to this
// not good
vector<unique_ptr<string>> vs {
unique_ptr<string>{ new string{"Doug"} },
unique_ptr<string>{ new string{"Adams"} }
};
However it may leak if one of the constructors fails. It's safer to use make_unique
:
// does not work
vector<unique_ptr<string>> vs {
make_unique<string>("Doug"),
make_unique<string>("Adams")
};
But... initializer_list
s always perform copies, and unique_ptr
s are not copyable. This is something really annoying about initializer lists. You can hack around it, or fallback to initialization with calls to emplace_back
.
If you're actually managing string
s with smart pointers and it's not just for the example, then you can do even better: just make a vector<string>
. The std::string
already handles the resources it uses.