从初始化器列表初始化unique_ptrs的容器失败,GCC为4.7
Initializing container of unique_ptrs from initializer list fails with GCC 4.7
我正在尝试以一种等效于Bjarne Stroustrup的C++11常见问题解答中的示例的方式初始化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/../../include/c++/4.7.0/bits/sstl_construct.h:77:7:错误:没有用于调用的匹配函数
'std::unique_ptr<std::basic_string<char> >::unique_ptr(std::basic_string<char>&)'
修复此错误的方法是什么?
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
是不可复制的。这是初始化器列表中非常令人讨厌的地方。您可以绕过它,或者通过调用emplace_back
回退到初始化。
如果您实际使用智能指针管理string
,并且这不仅仅是为了示例,那么您可以做得更好:只需制作一个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
的显式构造函数!
这个问题现在有了更好的答案,至少在C++17中是这样(C++11需要更多的努力)。由于这是第一个谷歌结果时,我寻找";初始化向量unique_ptr";,我认为它值得用解决方案进行更新。您可以使用变元函数,而不是使用初始值设定项列表。这是一个8行粗糙的小效用函数,看起来像这样:
#include<memory>
#include<vector>
#include<type_traits>
template <class T> auto move_to_unique(T&& t) {
return std::make_unique<std::remove_reference_t<T>>(std::move(t));
}
template <class V, class ... Args> auto make_vector_unique(Args ... args) {
std::vector<std::unique_ptr<V>> rv;
(rv.push_back(move_to_unique(args)), ...);
return rv;
}
我们现在可以用直观的语法制作一个向量:
auto vs = make_vector_unique<std::string>(std::string{"Doug"}, std::string{"Adam"});
您甚至可以使用它来生成派生类对象的向量。
class B {};
class D : public B {};
auto vb = make_vector_unique<B>(D{}, D{}, D{});
- 初始化迭代器错误 C++ 在 GCC 编译器中
- 为什么 gcc 会给我可能未初始化的警告 deque::insert 带有过滤范围
- GCC 匿名是未初始化的
- 为什么数组的 GCC 聚合初始化首先用零填充整个事物,包括非零元素?
- 为什么 gcc 警告只针对统一初始化缩小转换范围?
- 不可复制类数据成员的统一初始化导致gcc错误
- 如何在macOS中的旧扩展clang和gcc编译器中初始化数组和向量
- 你能初始化unique_ptrs "static const vectors"吗?(C++17 与 GCC 7.3)
- 如何实现使用 gcc-4.4 编译的大向量初始化?
- thread_local静态成员模板定义:初始化失败,GCC
- 初始化不可移动对象数组:为什么这样的代码无法在 GCC 上编译?
- 使用GCC 4.8构建错误:数组用作初始化器
- 为什么 GCC 6.3 在没有显式 C++11 支持的情况下编译此大括号初始化列表代码
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- 告诉 GCC 假设对象已初始化
- GCC缺少优化CTOR初始化器列表的机会
- 与lambda一起使用虚拟继承在初始化列表中捕获此问题的GCC错误
- GCC允许允许非初始化的ConstexPR
- 没有临时数组的列表初始化 - 在 GCC 中不起作用
- std::make_shared是否执行值初始化(GCC和clang不同意)