使用GCC 4.7初始化初始化程序列表中的unique_ptrs容器失败

我试图以等同于Bjarne Stroustrup的C ++ 11 FAQ的例子初始化一个std::vector<std::unique_ptr<std::string>>

 using namespace std; vector<unique_ptr<string>> vs { new string{"Doug"}, new string{"Adams"} }; // fails unique_ptr<string> ps { new string{"42"} }; // OK 

我看不出为什么这个语法会失败。 这种初始化容器有什么问题吗?
编译器的错误信息是巨大的; 我find的相关细分如下:

/usr/lib/gcc-snapshot/lib/gcc/i686-linux-gnu/4.7.0/../../../../include/c++/4.7.0 /bits/stl_construct.h:77 :7:错误:没有匹配函数调用'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'

有什么办法来解决这个错误?

unique_ptr的构造函数是explicit 。 所以你不能用new string{"foo"}隐式地创build一个。 它需要像unique_ptr<string>{ new string{"foo"} }

这导致我们这个

 vector<unique_ptr<string>> vs { unique_ptr<string>{ new string{"Doug"} }, unique_ptr<string>{ new string{"Adams"} } }; 

但是,如果其中一个构造函数失败,可能会泄漏。 使用make_unique更安全:

 vector<unique_ptr<string>> vs { make_unique<string>("Doug"), make_unique<string>("Adams") }; 

但是… initializer_list总是执行副本,而unique_ptr不可复制。 这是真正讨厌初始化列表的东西。 你可以绕过它 ,或者emplace_backemplace_back初始化。

如果你实际上用智能指针来pipe理string ,而不仅仅是这个例子,那么你可以做得更好:只要创build一个vector<string>std::string已经处理了它使用的资源。

在“修复”你的例子之后:

 #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 } 

我得到了非常明确的错误信息:

 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>*]' 

这个错误告诉我们不可能使用unique_ptr的显式构造器。