【问题标题】:Is it needed to delete a pointer that is not instantiated to a variable?是否需要删除未实例化为变量的指针?
【发布时间】:2016-08-09 16:40:44
【问题描述】:

我有一个Base 类,有两个派生类DerivedADerivedB 以及一个返回指针Base* 的工厂方法。

Base* GetClass(int choice)
{
    if (choice == 0)
        return new DerivedA();
    else if (choice == 1)
        return new DerivedB();
    throw std::invalid_argument("no no no");
}

DerivedADerivedB 都实现了一个方法,比如 GetDouble(),而这个方法是我对构建这些类中的任何一个感兴趣的唯一事情:

double d = GetClass(0)->GetDouble();

我的问题是:当我调用 GetClass(0) 时,我创建了一个应该删除的指针。但是,我没有将它实例化为对象。我还需要删除它吗?

类似:

Base* c = GetClass(0);
double d = c->GetDouble();
delete c;

这将如何与std::unique_ptr 一起使用?

提前谢谢你。

PS:我认为有一些相关的问题,比如thisthis,但我的问题更具体一些。

【问题讨论】:

  • “我没有将它实例化为对象”是什么意思。?当然,您正在泄漏内存(或其他资源)。
  • 返回一个std::unique_ptr<Base>,你就不会考虑删除它;-)
  • 我的意思是作为我给出的最后一个例子,当我首先将一个类实例化为Base* c,然后调用c->GetDouble(),然后删除c
  • @Girardi:“实例化”是您对模板所做的事情。最后一个示例的 C++ 描述将是“初始化变量 Base *c”。
  • @MSalters 感谢您的信息 =)

标签: c++ oop c++11 pointers


【解决方案1】:

使用std::unique_ptr,你就不用打电话给delete了。

std::unique_ptr<Base> GetClass(int choice)
{
    if (choice == 0)
        return std::make_unique<DerivedA>();
    else if (choice == 1)
        return std::make_unique<DerivedB>();
    throw std::invalid_argument("no no no");
}

您现在可以安全地调用:

double d = GetClass(0)->GetDouble();

这里发生的情况是:GetClass(0) 将返回一个 rvalue,它只会在 ; 处被销毁。因此,GetClass(0)-&gt;func-&gt;func-&gt;etc(); 之类的链式调用仍然会保留由GetClass() 返回的对象,直到;

记住; 是 C++ 最强大的功能之一。

【讨论】:

  • 如果我需要传递参数来构造DerivedADerivedB,我该怎么办?
  • @Girardi 将参数作为构造参数传递给std::make_unique
  • @Girardi,将其作为参数传递给std::make_unique.. 示例:std::make_unique&lt;DerivedA&gt;(arg1, arg2, arg3, ...etc);
  • 如果你能完全避免多态,一切都会更好: std::variant GetClass(int choice) { if (choice == 0) return DerivedA {}; else if (choice == 1) return DerivedB {}; throw std::invalid_argument("no no no"); }
【解决方案2】:

double d = GetClass(0)-&gt;GetDouble(); 是内存泄漏。你new 函数中的对象然后返回它。您使用返回的对象调用成员函数,然后丢弃表达式末尾的指针。由于您不再拥有指针,您可以再调用 delete 并释放您抓取的内存。

记住每次调用new/new[] 都需要匹配调用delete/delete[]

现在我们有了智能指针,我们可以使用std::unique_ptr 来解决这个问题。指针将为您管理内存,一旦超出范围,它将删除指针。

【讨论】:

    【解决方案3】:

    您实际上是在实例化一个对象,但没有存储指向它的指针,这已经是内存泄漏。每当您使用 new 分配对象时,作为程序员,您有责任确保相应地删除它。

    您的后一个示例可以正常工作。使用std::unique_ptr 可以省去这个担心,因为它会在销毁时自动删除其指向的对象。

    【讨论】:

      【解决方案4】:

      是的,你仍然需要delete它。

      GetClassDerivedADerivedB 动态分配存储空间。无论你是否将结果指针存储在任何地方,如果不删除,内存就会泄漏。

      正如您所说,std::unique_ptr&lt;Base&gt; 解决了您的问题。

      double d = GetClass(0)->GetDouble();
      

      如果GetClass 返回一个std::unique_ptr,那么它将在包含它的完整表达式的末尾被破坏,这将删除指针。

      【讨论】:

        【解决方案5】:

        如果你 new必须 delete (当然,很少有例外情况,例如当你在程序关闭期间故意泄漏对象以加速它并且你知道析构函数没有任何用处- 但这是一个边缘情况)。就那么简单。是否将new 的返回值分配给变量并不重要——内存仍然被分配并且需要被释放。如果您不跟踪返回的指针以稍后将其删除,它就会被泄露。

        使用std::unique_ptr 可以帮助您获得指针的所有权并在unique_ptr 超出范围时释放它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-24
          • 1970-01-01
          • 1970-01-01
          • 2020-10-10
          • 1970-01-01
          相关资源
          最近更新 更多