当我获得指向智能指针的指针时是否必须释放内存?

Do I have to deallocate memory when I get a pointer to a smart pointer?

我目前正在学习新的 c++ 知识,并且正在学习使用智能指针 (std::unique_ptr)。

假设我有 std::vectorstd::unique_ptr。在我的代码中的某个时刻,我需要遍历这个 stl 向量并挑选出我需要进行计算的对象。

  for (const auto& obj : objectList)
  {
    if(/*check if this is an object I need*/)
      OtherFunc(obj.get());
  }

  void OtherFun(object* obj)
  {
     std::vector tempVector.push_back(obj);
  }

在 OtherFunc 中,我将作为参数传入的这个对象添加到我保留的另一个 std::vector(表示为 otherVector)并进行计算。我不希望 OtherFunc 拥有对象的所有权。我只需要保留它们,这样我就不必每帧都传入对象。

我知道如果智能指针离开作用域(或者在我的情况下,退出程序),它们将自行取消分配,包含智能对象的对象 的 otherVector 会发生什么指针。我试着查看 cplusplus.com 上的文档,但无法得到问题的答案。我是否必须取消分配我保存在 otherVector 中的所有对象 ?或者由于对象最初是智能指针,我可以假设 otherVector 中的所有指针也将变为 null(因此,不会导致内存泄漏)。

您可以将另一个向量声明为 std::vector<object*>。它会持有对象指针但不会拥有它们,所以当它自己被释放时它不会尝试释放对象。当原始 std::vector<std::unique_ptr<object>> 被释放时,对象将被释放。只要确保原始向量比另一个向量长。

你可以拿一个指向std::unique_ptr里面的东西的指针来拿一个"peek",但这对智能指针来说是不可见的。如果唯一指针超出范围并删除其对象,则您拥有的指向其持有对象的任何普通指针都将无效。只要在唯一指针删除对象后不再使用您的常规指针,您就是安全的,但没有提供任何保护!

如果您需要多个指向具有不同生命周期的对象的指针,请考虑 std::shared_ptr

Documentation for get() 将声明它只是 returns 指向托管资源的非所有者指针,而不是 release(),它实际上将所有权转移到返回的指针。

这足以回答你的问题不应该清理那个指针。但是,还有一些其他问题需要注意。

首先要注意lifetime。管理资源仍然是智能指针的工作。如果智能指针清理干净,原始指针就会悬空。确保智能指针比原始指针长。如果你不能这样做,你应该使用 shared_ptr,它确保只有在所有关联的智能指针都完成后才清理资源。

现在有两种方法可以使用 shared_ptr 完成此任务。两者都需要将原始向量中的智能指针类型更改为shared_ptr。作为序言,假设您正在获取此指针并将其存储以备后用。当它被使用时,原始向量可能已经消失,其中的智能指针也随之消失。我还假设您需要一个原始指针来执行对资源的操作。也许您需要将其提供给 C 函数。

  1. 直接用。如果您希望资源至少在 OtherFun 需要它时使用它,那么这很好。 OtherFun 将采用 shared_ptr,现在可以通过直接传递向量元素来创建它,而无需使用 get

    实际上,在这里使用 get 会导致错误,因为 shared_ptr 需要从另一个 shared_ptr 构造,以便对资源进行正确的引用计数。 OtherFunshared_ptr 存储在任何需要的地方,并且存储的指针确保资源不会在原始向量消失时消失。

    当访问资源的时候,你从shared_ptr中获取你需要的原始指针,并确保本地shared_ptr比使用这个原始指针更容易,这比确保更容易它比矢量元素长。

  2. 商店weak_ptr。如果您希望原始向量是唯一负责资源的向量,但需要能够检查资源是否仍然有效并在有效时使用它,这很好。 OtherFun 将在任何需要的地方存储一个 weak_ptr。如果原始向量死亡,资源也会死亡。

    当需要从其他地方使用资源时,使用 lockweak_ptr 获得 shared_ptr(给出可能为空的 shared_ptr)或 shared_ptrweak_ptr 转换构造函数(抛出可能的异常)。您适当地检查资源是否仍然存在,并且 shared_ptr 确保它会一直存在直到您完成。那时,您可以像选项 1 一样继续并获得所需的原始指针。

除此之外,您还必须小心所有权。来自 get() 的原始指针绝不能变成任何类型的所有者。比如下面是错误的,会造成指针的双重删除:

void OtherFun(object* obj)
{
    std::unique_ptr<object> p(obj);
}

在这里,您已将 *obj 的唯一所有权授予 p,即使您调用 get()unique_ptr 仍然拥有 *obj。这类似于前面提到的 shared_ptr::get() 陷阱,您最终会遇到两个未关联的 shared_ptr 管理同一资源。

get() 本质上有些不安全并且会破坏封装。然而,为了使智能指针在现实世界中实用,这也是必要的。请注意,您可能会陷入陷阱,无论是从获得原始指针的生命周期开始,还是最终将那个非拥有原始指针变成所有者。这就是 release() 函数的用途。通常,当您不需要来自智能指针的原始指针以及仅将原始指针视为非所有者时,您会更加安全。