c++ 从智能指针获取所有权,并通过同一智能指针进一步访问原始指针

zbq4xfa0  于 2023-03-14  发布在  其他
关注(0)|答案(4)|浏览(156)

我有这样一个泄漏代码:

void f() {
  SomeClass *sc = new SomeClass;
  ...
  if (...) {
    g(sc); // g() takes ownership of memory pointed to by sc
  }
  ...
  sc->SomeMethod();
  ...
}

我想通过使用智能指针来消除泄漏,想到了以下解决方案:

void f() {
  smart_ptr<SomeClass> sc(new SomeClass);
  ...
  if (...) {
    g(sc.release()); // ownership is taken
  }
  ...
  sc->SomeMethod(); // sc points to the allocated memory regardless of whether ownership was taken or not
  ...
} // the memory is freed if ownership was not taken

尝试使用std::unique_ptr和std::shared_ptr。std::unique_ptr在释放后指向空指针,std::shared_ptr根本没有release()。手动增加std::shared_ptr的引用计数器会有所帮助,但正如我正确理解的那样,也没有这样的能力。
除了原始指针之外,还考虑使用std::unique_ptr,使代码保持原样,并在每次将原始指针传递给获得所有权的函数时调用release(),但这是一个非常模糊的解决方案。
我想知道是否有一个智能指针从标准库,适合我的目标,或者也许有一个理想或常见的技巧如何做,在我的情况下,或我可能错过了什么?

62lalag4

62lalag41#

您只需多写一点代码就可以保留一个本地的非所有者视图:

void g(std::unique_ptr<Foo> p);     // takes ownership

int main()
{
    auto p = std::make_unique<Foo>();
    Foo & local_view = *p;

    if (/* condition */) { g(std::move(p)); }

    local_view.do_stuff();
}
niknxzdl

niknxzdl2#

我不明白g取得所有权是什么意思,因为g退出后你仍然要使用指针,如果你总是想在g后使用指针,那么传递一个原始指针给g并在块的末尾释放指针会更有意义。
如果你想让g拥有所有权,并且只想在你的指针还存在的时候调用SomeMethod,那么就给g传递一个原始指针,并让它返回一个原始指针。如果指针在g中被释放,那么就返回nullptr,并在SomeMethod调用之前检查它。

7gcisfzg

7gcisfzg3#

可以使用shared_ptr,效果相同,shared_ptr没有release()函数,但是有reset()函数,我想这就是您要找的,但是要等到调用SomeClass::SomeMethod()之后才能调用sc.reset()

void g(shared_ptr<SomeClass> ptr);

void f()
{
   shared_ptr<SomeClass> sc(new SomeClass);

   if (/* check for condition */)
   {
      g(sc);
   }

   sc->SomeMethod();
   sc.reset();
}
vcudknz3

vcudknz34#

g() takes ownership of memory pointed to by sc
这会阻碍您的计划,因为g()拥有内存,所以允许在调用sc->SomeMethod()之前释放内存,这将导致未定义的行为。
一个简单而安全的解决方案可能是更改g()以接受shared_ptr而不是原始指针,这样调用方可以共享所有权。为了保留现有的调用站点,您可以同时引入g()的重载,该重载接受原始指针,从原始指针构造shared_ptr,然后调用接受shared_ptr的版本。
一个更复杂的解决方案可能涉及要求内存的新所有者为您调用SomeMethod。(创建一个标志来跟踪内存是否为您所有。)因为该内存不再是您可以访问的。您所做的事情就像买了一辆车,将其送给某人,然后偷偷溜进去开车兜风。这是盗窃。您将车送人,所以它不再是你的。你把记忆给了别人,所以它不再是你的。
最好的解决方案可能是在设计中后退一两步并重新评估。有时,重新组织代码以采用不同的方法会使这种情况消失,就像变魔术一样。特别是当f()的真实的主体又大又复杂时。(保持函数简单并专注于单个任务。)

相关问题