如何创建 unique_ptr 并将其添加到方法中的向量?

How can I create and add a unique_ptr to a vector in a method?

我正在尝试使用多态性来表示各种树(解析器的终端节点和非终端节点)。 classes Node 之一包含指向 Base 的子 classes 的智能指针向量。我想使用只接受 Node 引用的方法向该向量添加更多节点,而不必在 class 之外创建智能指针(或者这是糟糕的做法?)。

void addNode(const std::unique_ptr<Node> &&node) 重载有效,但我想使用
void addNode(const Node &&node) 过载。

无论我做什么,我似乎都无法在不破坏复制省略规则或调用 Node 的复制构造函数的情况下创建此智能指针并将其移动到向量中,我不确定为什么。看起来 make_unique 总是在调用 Node.js 的复制构造函数。我试过使用这些语句:

nodes.push_back(std::make_unique<Node>(node));

给出编译器错误 call to implicitly-deleted copy constructor。这是有道理的,以为我只需要 std::move 它。


nodes.push_back(std::move(std::make_unique<Node>(node)));

同样的错误,还有:moving a temporary object prevents copy elision.


nodes.push_back(std::make_unique<Node>(std::move(node)));

刚给出call to implicitly-deleted copy constructor.


nodes.push_back(std::move(std::make_unique<Node>(std::move(node))));

甚至尝试过这个,也给出了两个错误。

这是我的重现:

#include <iostream>
#include <string>
#include <vector>

class Base {};
class Node;
typedef std::vector<std::unique_ptr<Base> > Nodes;

class Node : public Base {
  Nodes nodes;

public:
  Node() {};
  void addNode(const Node &&node) {
    nodes.push_back(std::make_unique<Node>(node));
    //nodes.push_back(std::move(std::make_unique<Node>(node)));
    //nodes.push_back(std::make_unique<Node>(std::move(node)));
    //nodes.push_back(std::move(std::make_unique<Node>(std::move(node))));
  }

  void addNode(std::unique_ptr<Node> &&node) {
    nodes.push_back(std::move(node));
  }
};

int main()
{
  Node rootNode;
  rootNode.addNode(Node());
  rootNode.addNode(std::make_unique<Node>());
  return 0;
}

我正在使用 Clang++ 和 C++20 在 MacOS 上编译。

您想如何移动 const 对象?

应该是:

void addNode(Node &&node) {
    nodes.push_back(std::make_unique<Node>(std::move(node)));
}

通过移动,你修改了被移动的实例,所以它应该是可修改的。

Demo

错误是由于 void addNode(const Node &&node) 使用了一个 const 右值引用,这是非常可疑的实用程序的一个很大的奇怪之处(有一些极端情况它们可能有意义,请参阅 this answer 了解更多信息).

鉴于您不能从 const Node&& 移动(毕竟它是常量),隐式生成的移动构造函数 (Node(Node&&)) 无法匹配。

由于从 C++03 继承的旧怪癖 const T& 可以绑定到右值,因此 const T&& 可以衰减到 const T&。这导致编译器尝试调用Node(const Node&),又名复制构造函数,由于 std::vector<std::unique_ptr<Base>> 不可移动而被删除,这也是由于 std::unique_ptr<T> 不可移动。