【问题标题】:A handle to temporary unique_ptr returned by function函数返回的临时 unique_ptr 的句柄
【发布时间】:2018-06-21 05:17:53
【问题描述】:

我尝试阅读一些关于对象所有权的帖子,以及在复制构建本质上是被禁止的 unique_ptr 时如何应用一些例外。当然,我通过并通过引用返回它,因此不必涉及复制。

std::unique_ptr<T>& ptr_func(std::unique_ptr<T>& p) {
    return p;
}

将一个指针的实例传递给这个函数,是没有问题的。它基本上进入函数并保持不变,无论它指向什么。

现在我的问题来了:想象一下我感兴趣的指针指向一个包含多个属性的对象,我只能以函数的返回值的形式检索这个指针,例如

std::unique_ptr<T>& ptr_func() //say this function returns my pointer.

现在,假设检索这个指针需要相当多的计算(例如,通过迭代一个大向量),我想设置/获取它指向的对象的许多不同属性。然后,不能有第二个(临时)句柄来指向它所指向的指针或对象变得非常不切实际,因为我必须为每个单独的操作调用返回指针的函数。在一种已知情况下,编译器确实以某种方式创建了第二个引用:假设我将返回指针作为参数的函数传递给另一个函数,这会改变所指向对象的属性:

void set_attributes(std::unique_ptr ptr) {
    ptr->change_something();
    ptr->change_something_else();
}

像这样:

void set_attributes(function_returning_pointer())

在这种情况下,function_returning_pointer() 只被调用一次,而不管它的返回值在 set_attributes() 的主体中使用了多少次 这是如何工作的?

【问题讨论】:

  • "把一个指针的实例传给这个函数,是没问题的。基本上是进到函数里出来,不管它指向什么。" 然后,我看不出有什么理由不在这里使用普通指针。智能指针用于管理所有权,不应以这种方式过度使用。
  • 您确定要绕过unique_ptr吗?当您只需要对指向的对象的可修改引用时,然后以这种方式传递它。你从function_returning_pointer 哪里得到你的指针?你的 set_attributes 签名到底是什么样子的?它缺少模板参数,甚至可能缺少引用限定符?
  • 如果它“进入函数并输出不变”,你为什么不传递对const智能指针的引用? IE。 std::unique_ptr&lt;T&gt;&amp; ptr_func(std::unique_ptr&lt;T&gt; const&amp; p)。如果您想允许函数更改p 指向的位置,请仅传递可变引用。

标签: c++ constructor copy move unique-ptr


【解决方案1】:

std::unique_ptr&lt;T&gt;&amp; ptr_func() 是一个奇怪的签名:你可能会获得所有权……也可能不会。

您可能想要更清晰的功能:

T& get_ref();
T* get_ptr();
std::unique_ptr<T> take();

根据您的使用情况,set_attributes 应该是:

void set_attributes(MyObject& ptr) {
    ptr.change_something();
    ptr.change_something_else();
}

用法类似于

assert(function_returning_pointer() != nullptr);
set_attributes(*function_returning_pointer());

assert(get_ptr() != nullptr);
set_attributes(*get_ptr());

set_attributes(get_ref());

auto ptr = take();
assert(ptr != nullptr);
set_attributes(*ptr); // set_attributes(*take()) would be useless as object would be destroyed.

如果您真的想在不转让所有权的情况下继续传递unique_ptr,您的方法是:

void set_attributes(std::unique_ptr<MyObject>& ptr) { // prefer MyObject& or MyObject* instead
    assert(ptr != nullptr);
    ptr->change_something();
    ptr->change_something_else();
}

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2018-04-29
    相关资源
    最近更新 更多