【问题标题】:std::unique_ptr test before taking ownership取得所有权之前的 std::unique_ptr 测试
【发布时间】:2018-08-13 15:54:34
【问题描述】:

我有一个类,它基本上是一个队列,用于在 2 个线程之间传输动态分配的对象。第一个线程创建对象,第二个线程消耗它们。我使用 std::unique_ptr 将对象所有权从线程 1 传递到线程 2。

实际上调用将对象放入队列的方法是这样的:

queue.put(std::move(unique_ptr_to_my_object));

和签名:

bool Queue::put(std::unique_ptr<T> p);

问题是put() 方法必须检查一些条件来决定是否可以将对象添加到队列中。如果条件为假,则该方法仅返回假以指示它无法将对象添加到队列中,但该对象被销毁,因为所有权已被put() 取得。

所以我想知道这样重写put()是否可以,或者是否有更好的解决方案:

bool Queue::put(std::unique_ptr<T> &ref) {
    if(CANNOT_ADD)
        return false; // ownership remains in the calling function
    std::unique_ptr<T> p = std::move(ref); // we know we can add so take ownership
    /* ... */
}

【问题讨论】:

  • 我会将修改后的函数改为Queue::put(std::unique_ptr&lt;T&gt;&amp;&amp; ref)
  • @Tyker 不,它没有。它需要一个右值的引用。直到您使用它来分配或初始化它实际移动的东西。请记住,只有移动构造函数或移动赋值运算符才能真正移动某些东西。
  • @NathanOliver 还是为什么?在这种情况下,您可能确实希望限制为左值引用......否则如果放置失败,则只有暂时的剩余抱着婴儿。
  • @MartinBonner 为什么将函数限制为仅左值?如果我从某个函数中得到 unique_ptr 并且并不关心它是否已移入队列,为什么我需要先使其成为左值。
  • @James 我认为您的原始解决方案实际上是最好的解决方案。在失败的情况下返回对象是违反直觉的,并且使用反转逻辑(它有效地返回 false 表示成功,返回 true 表示失败)。我要做的唯一更改是重命名方法tryPut,以便一目了然它可能会失败。

标签: c++ move-semantics unique-ptr


【解决方案1】:

是的,没关系。替代方案是:

std::unique_ptr<T> Queue::put(std::unique_ptr<T> p) {
    if (CANNOT_ADD)
        return p; // Ownership returned to caller.
    /* ... */
    return {}; // Return empty nullptr to indicate success.
}

如果... 中的代码抛出,您的方式的优点是调用者保留所有权。

【讨论】:

  • 我认为,这样更好,因为没有条件取得所有权,这有点痛苦。
  • @SergeyA 是的,这也是我的想法,但这真的取决于 OP 试图解决的问题。
  • 我看到的麻烦是put()的用户仍然可以错误地使用它。如果他们调用put() 并且不对结果做任何事情,那么当条件失败时对象会被静默删除。我更喜欢通过引用传递。除非put() 明确接受,否则所有者保留所有权。
【解决方案2】:

您可以将函数的签名更改为:

std::unique_ptr<T> Queue::put(std::unique_ptr<T> p);

因此,如果该函数无法获取该对象,它将返回该指针,否则返回 nullptr。另一种解决方案是有条件地取得所有权:

bool Queue::put(std::unique_ptr<T> &&p);

只有在成功的情况下才能移出对象。在这种情况下,接受右值引用比接受左值引用更好,至少有两个原因:

  1. 您仍然可以暂时通过。
  2. 您需要在调用代码中显式使用std::move

尽管您可以在std::move 之后使用该指针这一事实使得该变体的可读性降低。

【讨论】:

    猜你喜欢
    • 2016-01-30
    • 1970-01-01
    • 2011-03-02
    • 2015-05-16
    • 2017-08-31
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    相关资源
    最近更新 更多