【问题标题】:std::unique_ptr::release() vs std::move()std::unique_ptr::release() 与 std::move()
【发布时间】:2016-03-16 08:39:02
【问题描述】:

我有一个表示运行时上下文并构建树的类,树根保存在unique_ptr 中。构建树完成后,我想提取树。这是它的样子(不可运行,这不是调试问题):

class Context {
    private:
    std::unique_ptr<Node> root{new Node{}};
    public:
    // imagine a constructor, attributes and methods to build a tree
    std::unique_ptr<Node> extractTree() {
        return std::move(this->root);
    }
};

所以我使用std::move()Context 实例中提取根节点。

但是,还有其他使用 std::move() 的替代方法,例如:

std::unique_ptr<Node> extractTree() {
    // This seems less intuitive to me
    return std::unique_ptr<Node>{this->root.release()};
}

std::move() 是最佳选择吗?

【问题讨论】:

  • 移动后需要从this-&gt;root调用reset。你最好也阅读这个答案stackoverflow.com/a/20850223/555515
  • @neuront:不,你没有。
  • 移动src后包含nullptr,reset没有意义!
  • 如果您发现自己在 unique_ptr 上调用 release(),则警告您的逻辑可能不合理。
  • @RichardHodges 除非您必须将所有权传递给 C API。

标签: c++ c++11


【解决方案1】:

您绝对应该使用第一个版本,因为第二个版本基本上完成了第一个版本所做的所有事情,但代码更多但可读性更低。

从哲学上讲,第二个版本移动唯一指针,不多也不少。那么为什么要绕着桌子转,而不是使用已经存在的、更易读、更惯用的std::unique_ptr(std::unique_ptr&amp;&amp;) 呢?

最后,如果你的智能指针在未来某处将持有 custom deleter ,第一个版本将确保删除器也移动,第二个版本不会移动删除器。我绝对可以想象一个程序员使用release 从自定义删除器唯一指针中构建非自定义删除器唯一指针。使用移动语义,程序将无法编译。

【讨论】:

    【解决方案2】:

    你所做的很危险。一旦你调用了getTree(),你就不能再次调用它,这从界面上看不清楚。您可能需要重新考虑您的设计(例如,shared_ptr 可能会做得更好,或者只是将根存储为原始指针并手动处理释放)。

    无论如何,如果您想坚持自己的设计,使用std::move 是两者中更好的选择,因为它使您的意图更加清晰。

    编辑:显然“不得”在我不知道的英语中具有特殊的禁忌含义。可以根据需要调用该函数两次或多次,但如果连续执行,则不会返回指向有效对象的指针。

    【讨论】:

    • 第二次拨打getTree()没有问题。它只会返回一个空的unique_ptr
    • 为什么不能两次调用getTree()?一旦根被移动,它就会被设置为nullptr,因此再次从它移动会得到一个nullptr,这对于一个空对象来说似乎是一个非常合理的行为。
    • 从函数签名和名称来看,您通常会假设您的整个对象基本上变得无法使用吗?我不会。如果他想保持这种状态并且行为是他想要的,一切都很好,但他可能没有意识到后果。
    • 我认为期望get...() 调用具有const 行为是合理的。我认为将函数重命名为 extractTree() 之类的名称将更清楚地传达这样一个事实,即 Context 在此调用后将不再有树。
    • @kamikaze:这就是为什么我发现从这样的函数中得到 unique_ptr 令人惊讶。 ;-) 另请注意,我可以做getTree()-&gt;something(),甚至从未意识到我只是用核弹击中了树,想知道为什么该声明第二次吹响了。
    猜你喜欢
    • 2016-03-21
    • 2014-02-27
    • 2016-07-08
    • 2013-05-18
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    • 1970-01-01
    相关资源
    最近更新 更多