如果函数 returns a std::unique_ptr,假设每个返回值都是一个新对象是否合理?

If a function returns a std::unique_ptr, is it reasonable to assume each returned value is to a new object?

我正在学习 std::unique_ptr,试图理解它代表什么。

给定一个 returns 一个 unique_ptr 的函数(我无法控制),是否 implied/well 理解每个调用 returns 一个 unique_ptr指向一个新对象(不同于任何先前的调用)?

举例来说,下面的代码在退出时产生双重释放,我希望我能正确理解原因:unique_ptrs 在销毁时删除它们的底层对象;因此,两个 unique_ptr 封装相同的 memory/object 会导致在破坏第二个时出现双重释放。所以下面的函数实现getUniquePtr()会不会被commonly/implicitly理解为不合理?

// main.cpp
#include <memory>
#include <iostream>

std::unique_ptr<int> getUniquePtr() {
  static int* p = new int(42);
  return std::unique_ptr<int>(p);
}

class PtrOwner {
public:
  std::unique_ptr<int> p_;
};

int main( int argc, char* argv[] ) {
  PtrOwner po1;
  PtrOwner po2;
  po1.p_ = getUniquePtr();
  po2.p_ = getUniquePtr();

  return 0;
}

应该假设,如果一个函数returns std::unique_ptr<T>,那么returned智能指针指向一个当前未被管理的对象其他人。这并不一定意味着它总是指代不同的对象。只要遵循这个约定,就可以避免双重错误。如果违反这个约定,就会出现double-free的bug。

例如,如果您看到这样的函数:

std::unique_ptr<T> foo(std::unique_ptr<T> arg);

在某些情况下,此函数可能会 return std::move(arg) 或者它可能会破坏 arg 和 return 一些其他指针。 (您必须阅读文档才能知道它的作用)。这意味着您可以这样做:

auto t = std::make_unique<T>();
t = foo(std::move(t));
t = foo(std::move(t));

在这种情况下,foo 可能只是 return 相同的指针值两次,这是绝对安全的。这个例子看起来很愚蠢,但希望它能表达我的观点。

是的,您的假设(大部分)是正确的。 unique_ptr 独占该对象,这意味着在任何给定时间任何两个 unique_ptr 都不应指向同一个对象。

正如其他人所指出的,这并不能保证多次调用同一函数 return 的不同对象。这是因为你可以传递所有权(通过移动它),所以如果你将所有权传回一个函数,就像在 Brian 的回答中那样,它很可能再次 return 同一个对象,而不违反任何规则。

如果您决定使用智能指针来管理对象,请尽量避免使用 new 和 delete。要创建属于 unique_ptr 的对象 T,请使用 make_unique<T>。这样就避免了为同一个对象创建多个unique_ptr的错误。正是由于这个原因,unique_ptr 不可复制。换句话说,你的 getUniquePtr 应该这样实现:

return std::make_unique<int>(42);

从原始指针构造智能指针(与使用 make_unique 相对)的少数几个原因之一是当您有现有代码或使用原始指针的库时,您无法更改。