C++如何将unique_ptr的队列添加到向量中

Mik*_*lin 5 c++ stl copy-constructor unique-ptr

简化代码:

#include <queue>
#include <memory>
#include <vector>

class Foo {
public:
    Foo() {};
    virtual ~Foo() {}
};

int main()
{
    std::queue<std::unique_ptr<Foo>> queue;
    auto element = std::make_unique<Foo>();
    queue.push(std::move(element));
    std::vector<std::queue<std::unique_ptr<Foo>>> vector;
    // Error 1
    vector.push_back(queue); 
    // Error 2
    vector.push_back(std::move(queue));
    // Error 3
    vector.push_back({});
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误:

'std :: unique_ptr> :: unique_ptr(const std :: unique_ptr <_Ty,std :: default_delete <_Ty >>&)':尝试引用已删除的函数

显然复制了unique_ptr的复制,但我不是要复制它.我呢?

asc*_*ler 3

这有点棘手。如果以下两件事之一为真,则所有std::vector<T>可以增加向量大小的函数都必须以异常安全的方式进行:

\n\n
    \n
  • T有一个移动构造函数,保证它永远不会抛出任何异常;或者,

  • \n
  • T有一个复制构造函数。

  • \n
\n\n

因此,在大多数实现中,如果T声明了移动构造函数nothrow或等效的vector移动构造函数,则将使用 的移动构造函数T来执行这些操作。如果没有,并且T具有复制构造函数,vector则将使用复制构造函数,即使T具有移动构造函数。

\n\n

这里的问题是,std::queue总是声明它有一个复制构造函数,即使该复制构造函数实际上无法实例化,并且总是声明它有一个可能抛出的移动构造函数,即使容器成员的移动构造函数保证它不会抛出。

\n\n

标准在 [queue.defn] 中将这些指定为:

\n\n
namespace std {\n  template<class T, class Container = deque<T>>\n  class queue {\n    // ...\n  public:\n    explicit queue(const Container&);\n    explicit queue(Container&& = Container());\n    // ...\n  };\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

可以通过多种方式改进此类模板定义,使其更加“SFINAE 友好”并避免出现类似您遇到的问题。(也许有人可以检查其他具有类似问题的课程并向图书馆工作组提交提案。)

\n\n
    \n
  1. Container更改移动构造函数以承诺如果类型做出相同的承诺则不会抛出异常,通常使用如下语言完成:

    \n\n
    explicit queue(Container&& rhs = Container()) nothrow(see below);\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    备注:里面的表达式noexcept等价于is_\xc2\xadnothrow_\xc2\xadmove_\xc2\xadconstructible_\xc2\xadv<Container>

  2. \n
  3. Container如果类型不可复制,则更改要删除的复制构造函数,通常使用如下语言完成:

    \n\n
    explicit queue(const Container&);\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    备注:is_\xc2\xadcopy_\xc2\xadconstructible_\xc2\xadv<Container>除非是,否则该构造函数应被定义为已删除true

  4. \n
\n