繁体   English   中英

使用std :: unique_ptr有什么好处 <T> 而不是std :: unique_ptr <T> ?

[英]Are there any advantages of using std::unique_ptr<T>& instead of std::unique_ptr<T>?

使用std::unique_ptr<T>&而不是std::unique_ptr<T>有什么好处吗? 例如,在函数参数中?

有几种不同的情况

  1. 您想将所有权转移到该功能
    • 使用std::unique_ptr<T>
  2. 您希望允许该函数修改指针
    • 使用std::unique_ptr<T> &
  3. 您希望允许该函数修改指针
    • 在呼叫站点使用T &和取消引用
    • 如果指针可能为null,则使用T *并在调用站点调用unique_ptr::get
  4. 您希望允许该函数观察指针
    • 使用const T & ,并在呼叫站点取消引用
    • 如果指针可能为null,则使用const T *并在调用站点调用unique_ptr::get
  5. 您希望允许该函数具有指针的副本
    • 使用T ,并在呼叫站点取消引用
  6. unique_ptr<T>的集合上有一个ranged-for循环(或<algorithm>调用),并且想要观察值,并且没有ranges::indirect (或类似
    • 使用auto & ,并且知道它被推断为std::unique_ptr<T> & (或const std::unique_ptr<T> &如果集合是const ),所以你必须在循环体中取消引用

由于std::unique_ptr无法通过设计进行复制,因此只能通过将指针的所有权传递给函数来调用std::unique_ptr<T>的函数(即移动构造)。 调用代码将无法再访问指针。

使用std::unique_ptr<T>& ,您允许函数“看到”指针并访问其成员,但调用代码保留所有权,因此仍然可以自己使用它。

std :: unique_ptr只能移动,所以如果你按值传递unique_ptr,那么你不能在函数调用后提取它的内容,但如果你通过引用传递,那么可以检索值。 以下是相同的示例代码:

#include <iostream>
#include <memory>
void changeUniquePtrReference(std::unique_ptr<int>& upr)
{
    *upr = 9;   
}
void changeUniquePtrValue(std::unique_ptr<int> upv)
{
    *upv = 10;
}
int main()
{
  std::unique_ptr<int> p(new int);
  *p =8;
  std::cout<<"value of p is "<<*p<<std::endl;
  changeUniquePtrReference(p);
  std::cout<<"value of p is "<<*p<<std::endl;
  changeUniquePtrValue(std::move(p));
  std::cout<<"Memory deallocated so below line will crash.. "<<std::endl;
  std::cout<<"value of p is "<<*p<<std::endl;

  return 0;
}

这两种变体是不同的,适用于特定情况。

如果您的函数采用std::unique_ptr<T> ,这意味着您对托管对象拥有所有权并将其删除或将其保存在其他位置。

如果你采用std::unique_ptr<T> & ,你不会获得所有权,但你可以改变指针指向的内容,例如通过将其重置为不同的对象。

如果您不打算更改指针本身,则只需传递T&或const T& ,具体取决于您是否计划修改对象。 传递const std::unique_ptr<T> &是没有用的,因为这不会让你做更多的事情而不是T& ,具有潜在的额外间接的缺点和对参数的不必要的限制。

Herb Sutter解释了将智能指针传递给具有所有可能变化的函数的所有缺点和优点。 请阅读文章了解更多信息,它非常好:

简而言之,将unique_ptr传递给没有引用的函数是没有意义的,除非你的预期行为是放弃指针的所有权。

就个人而言,我只看到一个你应该传递对unique_ptr的引用的情况:那就是你调用的方法可能在内部 决定删除对象,或者放弃它。 这应该是非常罕见的,因为所有者放弃了对所有权的决定,老实说,这不是很好的设计。

如果子对象总是占用所有权或删除对象,则参数类型应为unique_ptr 并立即传递所有权。

如果子对象只是想访问指针内容,则参数应该是原始指针。 您可以为const unique_ptr reference创建一个参数,这将阻止您释放它,但有什么意义呢? 如果你觉得你需要一个超出原始的约定,你可以装饰那个原始的指针类型名称,这样你就知道你不拥有它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM