提问者:小点点

从初始值设定项列表初始化unique_ptrs的容器失败,GCC 4.7


我试图初始化一个std::vector>,其方式相当于BjarneStrousstrup的C++11常见问题解答中的一个示例:

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/../../../include/C++/4.7.0/bits/stl_construct.h:77:7:错误:调用'std::unique_ptr没有匹配函数; >::unique_ptr(std::basic_string&)'

修复这个错误的方法是什么?


共2个答案

匿名用户

unique_ptr的构造函数是explicit。 所以您不能用fromnew string{“foo”}隐式创建一个。 它需要类似于unique_ptr{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_lists始终执行复制,unique_ptrs不可复制。 这是关于初始值设定项列表的一些真正令人讨厌的东西。 您可以绕过它,或者通过调用emplace_back返回初始化。

如果您实际使用智能指针管理string,而且这不仅仅是为了示例,那么您可以做得更好:只需创建一个vectorstd::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的显式构造器!