如何正确地将所有权从原始指针移动到 std::unique_ptr?

How to correctly move ownership from raw pointer to std::unique_ptr?

我的做法是:

class SomeClass
{
    std::vector<std::unique_ptr<MyObject>> myObjects;
public:
    void takeOwnership(MyObject *nowItsReallyMyObject)
    {
        myObjects.emplace_back(std::move(nowItsReallyMyObject));
    }
};

我做的是否正确,或者有更好的解决方案吗?

您应该从一开始就接受unique_ptr

class SomeClass
{
    std::vector<std::unique_ptr<MyObject>> myObjects;
public:
    // tells the world you 0wNz this object
    void takeOwnership(std::unique_ptr<MyObject> myObject)
    {
        myObjects.push_back(std::move(myObject));
    }
};

通过这种方式,您可以清楚地表明您拥有所有权,还可以帮助其他程序员避免使用原始指针。

进一步阅读:CppCoreGuidelines R.32

move 是多余的。

我自己,我会这样做:

void takeOwnership(std::unique_ptr<MyObject> nowItsReallyMyObject)
{
    myObjects.emplace_back(std::move(nowItsReallyMyObject));
}

因为我想尽可能 "out" 移动 unique_ptr 所有权语义。

我可能会写这个效用函数:

template<class T>
std::unique_ptr<T> wrap_in_unique( T* t ) {
  return std::unique_ptr<T>(t);
}

所以呼叫者可以:

foo.takeOwnership(wrap_in_unique(some_ptr));

但更好的是,可以将 unique_ptr 语义的边界尽可能地推开。

我什至可以:

template<class T>
std::unique_ptr<T> wrap_in_unique( T*&& t ) {
  auto* tmp = t;
  t = 0;
  return std::unique_ptr<T>(tmp);
}
template<class T>
std::unique_ptr<T> wrap_in_unique( std::unique_ptr<T> t ) {
  return std::move(t);
}

这让呼叫者可以更轻松地将他们的 T* 转换为 unique_ptr。他们所有的 T*->unique_ptr<T> 现在都包裹在 std::move 中,并将源指针归零。

所以如果他们有

struct I_am_legacy {
  T* I_own_this = 0;
  void GiveMyStuffTo( SomeClass& sc ) {
    sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
  }
};

代码可以转化为:

struct I_am_legacy {
  std::unique_ptr<T> I_own_this;
  void GiveMyStuffTo( SomeClass& sc ) {
    sc.takeOwnership( wrap_in_unique(std::move(I_own_this)) );
  }
};

它仍然可以编译并且工作相同。 (与 I_own_this 的其他交互可能需要更改,但其中一部分已经 unique_ptr 兼容)。