仅移动对象的 std::vector 的支撑初始化失败

Don*_*tch 6 c++ stdvector stdinitializerlist braced-init-list

我可以简洁地(用大括号)初始化以下 6 种情况中的 5 种:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n
可复制的只移动的
大批是的是的
标准::数组是的是的
std::向量是的
\n
\n

一种似乎不起作用的情况是尝试初始化仅移动对象的 std::vector ;无法编译,并显示消息,例如:“错误:调用 \'std::unique_ptr\' 的隐式删除复制构造函数”。

\n

为什么是这样?是否有适用于这种情况的替代初始化语法?

\n

下面的程序演示了。

\n
/*\nclang++ -std=c++14 -W -Wall -Werror question.cc -o question\nclang++ -std=c++17 -W -Wall -Werror question.cc -o question\nclang++ -std=c++20 -W -Wall -Werror question.cc -o question\nclang++ -std=c++2b -W -Wall -Werror question.cc -o question\ng++ -std=c++14 -W -Wall -Werror question.cc -o question\ng++ -std=c++17 -W -Wall -Werror question.cc -o question\ng++ -std=c++20 -W -Wall -Werror question.cc -o question\ng++ -std=c++2b -W -Wall -Werror question.cc -o question\n*/\n#include <array>\n#include <memory>\n#include <vector>\n\nint main(int, char **) {\n  {\n    // I can initialize an array, std::array, or std::vector of\n    // copyable objects concisely as follows:\n    std::shared_ptr<int> a[] = {std::make_shared<int>(42)};\n    std::shared_ptr<int> b[] {std::make_shared<int>(42)};\n    std::array<std::shared_ptr<int>, 1> c = {std::make_shared<int>(42)};\n    std::array<std::shared_ptr<int>, 1> d {std::make_shared<int>(42)};\n    std::vector<std::shared_ptr<int>> e = {std::make_shared<int>(42)};\n    std::vector<std::shared_ptr<int>> f {std::make_shared<int>(42)};\n  }\n  {\n    // And I can also initialize an array or std::array (but not a std::vector)\n    // of move-only (non-copyable) objects similarly:\n    std::unique_ptr<int> a[] = {std::make_unique<int>(42)};\n    std::unique_ptr<int> b[] {std::make_unique<int>(42)};\n    std::array<std::unique_ptr<int>, 1> c = {std::make_unique<int>(42)};\n    std::array<std::unique_ptr<int>, 1> d {std::make_unique<int>(42)};\n\n    // But if I try to do the same with std::vector of move-only\n    // objects, it fails to compile.\n    // clang++:\n    //   "error: call to implicitly-deleted copy constructor\n    //    of \'std::unique_ptr<int>\'"\n    // g++ (c++14, c++17):\n    //     "error: static assertion failed: result type must be constructible\n    //     from input type"\n    // g++ (g++20, g++2b):\n    //     "error: use of deleted function\n    //      \xe2\x80\x98std::unique_ptr<_Tp, _Dp>::unique_ptr(\n    //      const std::unique_ptr<_Tp, _Dp>&)\n    //      [with _Tp = int; _Dp = std::default_delete<int>]\xe2\x80\x99\n#if 1  // (hard code to 1 for error, 0 for successful compile)\n    std::vector<std::unique_ptr<int>> e = {std::make_unique<int>(42)};\n    std::vector<std::unique_ptr<int>> f {std::make_unique<int>(42)};\n#endif\n    // The most concise workaround I have found is as follows.\n    // (This would not work if I wanted to make the vector const.)\n    // Notice that initializer-list initialization does succeed,\n    // as long as the initializer list is empty!\n    std::vector<std::unique_ptr<int>> e_workaround = {};\n    e_workaround.push_back(std::make_unique<int>(42));\n    std::vector<std::unique_ptr<int>> f_workaround {};\n    f_workaround.push_back(std::make_unique<int>(42));\n  }\n\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

for*_*818 7

您尝试调用的构造函数是(https://en.cppreference.com/w/cpp/container/vector/vector

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
Run Code Online (Sandbox Code Playgroud)

constexpr自 C++20 起)

参数是 a std::initializer_list<T>, 按值。您的电话与以下内容没有什么不同:

auto u = std::make_unique<int>(42);
std::vector<std::unique_ptr<int>> e = {u};
Run Code Online (Sandbox Code Playgroud)

如果这从 开始u,那将是一个糟糕的意外。另一方面,移动 astd::initializer_list几乎没有什么用处,因为它只是一个数组的轻量级代理T(复制 astd::initializer_list并不复制元素)。

std::array您的原始 c 数组代码可以工作,因为它是聚合初始化。那里不std::initializer_list涉及构造函数。

解决方法看起来没问题。您可以编写一个函数来初始化向量

/*const*/ std::vector<std::unique_ptr<int>> e = from_ints({42,2,31});
Run Code Online (Sandbox Code Playgroud)

当向量为 时,这也适用const