c++ - "result type must be constructible from value type of input range"尝试将 stack<unique_ptr>(或 deque)插入 vector 时

标签 c++

我基本上有这样的东西(我更改了变量名称,如果看起来很奇怪,抱歉)

#include <stack>
#include <memory>
#include <vector>

struct Sequence {
    std::stack<std::unique_ptr<int>> numbers;
    // It works if I change it to this
    //std::stack<std::unique_ptr<int>, std::vector<std::unique_ptr<int>>> numbers; 
    Sequence(const std::vector<int> &v) {
        for (int i : v) {
            numbers.push(std::make_unique<int>(i));
        }
    }
};

int main() {
    // constructing alone works fine
    // Sequence s{{3, 1, 5}};   

    // but pushing it into a vector gives an error
    std::vector<Sequence> ts;
    ts.emplace_back(std::vector<int>{1, 5, 2});
    return 0;
}
编译给出了这个错误:
/usr/include/c++/10/bits/stl_uninitialized.h:137:72: error: static assertion failed: result type must be constructible from value type of input range
  137 |       static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
当我尝试将 Sequence 放入 vector 中时。但是,如果我将底层堆栈容器从 std::deque 更改为 std::vector,它会起作用。我的猜测与移动和复制 unique_ptr 有关,但我真的不明白其中的细微差别——有人知道发生了什么吗?

最佳答案

这似乎是 std::vector 旧的“move if noexcept”问题的一个实例。简而言之,std::vector<Sequence>::push_back 可能需要重新分配,在这种情况下,它会使用 Sequence 的复制构造函数,因为它无法证明移动构造函数不会抛出异常。为了强制它使用移动构造函数,您必须将 Sequence 的复制构造函数标记为已删除:

Sequence(const Sequence&) = delete;
Sequence(Sequence&&) = default;
这应该使您的代码编译。
当堆栈的底层容器更改时问题消失的原因是 std::vector 是 noexcept 可移动的,而 std::deque 可能不是(并且,在您似乎正在使用的 libstdc++ 中,它不是)。这个 noexcept-movability 属性由包含的 std::stack 传播到 Sequence 的隐式移动构造函数。因此,使用底层 vectorSequence 将自己宣传为 noexcept-movable ,并且封闭的 vector 做正确的事情。对于底层双端队列, Sequence 将自己宣传为 not-noexcept-movable,封闭的 vector 实例化复制构造函数,并且实例化失败,因为它需要 unique_ptr 的复制构造函数。

关于c++ - "result type must be constructible from value type of input range"尝试将 stack<unique_ptr>(或 deque)插入 vector 时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64758775/

相关文章:

c++ - 写出文件时出现奇怪的 glibc 错误

c++ - 父类(super class)不能有派生类的指针?

C++:成员指针已初始化?

c++ - 这个单例类会在销毁时自动释放内存吗?

c++ - 将 void* 转换为仅在运行时已知的几种类型

c++ - 使用函数参数隐藏成员函数

c++ - 如何将值附加到命令行参数数组?

c++ - 父类使用默认构造函数;子类的析构函数被意外调用

c++ - 向不同 header 中定义的类中的函数授予友元

c++ - thread.join() 如何工作?