初始化初始化列表中unique_ptrs的容器因GCC 4.7而失败

时间:2012-03-08 13:18:13

标签: c++ compiler-errors initialization c++11

我尝试以与Bjarne Stroustrup's 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

我看不出这种语法失败的原因。这种初始化容器的方式有问题吗? 编译器错误消息很大;我找到的相关部分如下:

  

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

修复此错误的方法是什么?

2 个答案:

答案 0 :(得分:58)

unique_ptr的构造函数是explicit。因此,您无法使用new string{"foo"}隐式创建一个。它需要像unique_ptr<string>{ new string{"foo"} }

这引导我们进入这个

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

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

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

但是...... initializer_list总是执行副本,unique_ptr s不可复制。这对初始化列表非常烦人。您可以通过调用emplace_backhack around it或回退到初始化。

如果您实际使用智能指针管理string并且不仅仅是为了示例,那么您可以做得更好:只需制作一个vector<string>std::string已经处理了它使用的资源。

答案 1 :(得分:3)

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

#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的显式构造函数。