使用 std::<T>unique_ptr& 代替 std::unique_ptr 有什么好处<T>吗?

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

本文关键字:ptr gt unique lt std 使用 代替 什么      更新时间:2023-10-16

使用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,则为const std::unique_ptr<T> &(,因此必须在循环体中取消引用

由于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&或一个常量T&,具体取决于是否计划修改对象。传递const std::unique_ptr<T> &是没有用的,因为这并不能使您比传递T&做更多的事情,还有潜在的额外间接性和对参数的不必要限制的缺点。

Herb Sutter解释了将智能指针传递到具有所有可能变体的函数的所有利弊。请阅读文章了解更多信息,它真的很好:

简而言之,除非您的预期行为是放弃指针的所有权,否则在没有引用的情况下将unique_ptr传递给函数是没有意义的。!

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

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

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