【问题标题】:list of pointers initialize and release memory指针列表初始化和释放内存
【发布时间】:2015-12-12 06:42:19
【问题描述】:

使用list管理内存的好习惯有哪些,

当我们不再需要它时动态分配和释放(免费)。为了保持程序轻巧并避免内存泄漏,请确保良好的内存管理(我现在这是一个广泛的问题)

  1. 如何初始化一个指向最初包含 N 个项目的对象的指针列表?我应该使用 operator new 来分配内存吗?
  2. 如果我想从列表和程序存储空间中完全删除(释放)一个项目,我应该使用 pop 还是 remove 或 erase ?区别?
  3. 我应该在迭代列表时使用 operator delete 还是 .erase .remove 足以释放空间?

.

   class myclass { /* whatever attributes, methodes */  };

    list<myclass *> lst (5); //5 pointers will be NULL this way

for (list<myclass *>::iterator it=lst.begin(); it != lst.end(); it++)  {
   myclass *obj= *it;
   delete obj;              //error
   it = lst.erase(it);
}

【问题讨论】:

  • 使用smart pointers 并避免原始拥有指针。
  • 我什至不知道智能指针是什么我不熟悉 c++
  • C++ 中的列表和相关容器旨在保存对象并为您处理所有内存管理。除非你有充分的理由,否则根本不要使用指针。
  • @Beta:这对于 list 来说可能是一个公平点,它是一个专门的容器。它当然不适用于std::vector,它应该是您的默认容器。
  • @MSalters:为什么它不适用于std::vector?将指针放在向量中如何使它们更易于理解?

标签: c++ pointers memory memory-management linked-list


【解决方案1】:

C++ 具有值语义。一个列表拥有它上面的对象。无论是int(内置类型)、std::string(库类型)还是myclass(您的)列表,都是如此。确保您的课程可以复制(或至少可以移动,但这是一个高级主题)。还要确保你的类析构函数正常工作,因为list::clear 会调用它。

最初不要尝试使用指针列表。当你这样做时,使用 smart 指针列表,但这已经是一个高级主题了。应该完全避免使用“哑”指针列表。

【讨论】:

    【解决方案2】:

    虽然我认为您应该听听其他人所说的话,但我想我仍然会回答您的问题,以便您在需要了解它们时知道答案。智能指针现在绝对是最好用的,但是当我在 C++ 中学习指针时,我最初使用的是 new/delete,我觉得它比直接使用智能指针更能帮助你理解(我知道你说过你不知道它们是什么)是,所以他们只是为你管理内存)。

    如何初始化一个指向最初包含 N 个项目的对象的指针列表?我应该使用 operator new 来分配内存吗?

    正如您所做的那样,list&lt;myclass *&gt; lst (5) 可以很好地制作您的指针列表,是的,您应该为列表中的每个元素使用 new 以便在那里分配内存。例如,

    list<myclass*>::iterator it = lst.begin();
    *it = new myclass();
    

    如果我想从列表和程序内存空间中完全删除(释放)一个项目,我应该使用 pop 还是 remove 或 erase ?区别?

    要从列表中删除一个元素,您可以使用此处的列表擦除功能:http://www.cplusplus.com/reference/list/list/erase/ 这将从列表中删除元素,但是如果使用指针,请在此处小心,因为您需要确保在擦除此节点之前释放列表节点所持有的指针(见下文)

    我应该在迭代列表时使用 operator delete 还是 .erase .remove 足以释放空间?

    .erase 将从列表中删除元素,但它不会为您释放指针,您将明确需要执行类似的操作。

    list<myclass*> lst(5);
    list<myclass*>::iterator it = lst.begin();
    *it = new myclass();
    // and when you're ready to delete a node
    if(*it != NULL)
         delete *it;
         lst.erase(it);
    

    另外,在你的 for 循环中,一定要像我一样检查指针是否为 NULL,然后再删除它。这可能是您在删除调用时遇到错误的原因。由于不允许将内存存储在NULL,显然不允许删除那里的内存。这会给你一个分段错误。在删除之前检查 NULL 总是好的,以防万一,除非您确定它将保存数据。

    希望这会有所帮助。这不是使用较新版本的 C++ 的最佳方法,但它应该可以回答您提出的问题。

    【讨论】:

    • 感谢它确实回答了我的问题,我稍后会查看智能指针,我忘记了我应该在删除后将 ptr 设置为 NULL 还是删除 ptr 无用; ptr = 0;
    • 如果您打算立即删除该列表元素,则没有必要,因为该变量将与列表元素一起删除,但如果您只是删除指针指向的内容而不是列表元素,绝对将其设置为 NULL。在您更好地理解 C++ 之前,现在始终将其设置为 NULL 可能只是最佳实践。比后悔更安全。另外,如果有帮助请点赞!我正在努力提高我的声誉!刚开始使用这个网站。 ;D
    【解决方案3】:
    1. 如何初始化一个指向最初包含 N 个项目的对象的指针列表?我应该使用 operator new 来分配内存吗?

    不要。让列表处理分配和释放。

    lst.push_back(myclass());
    

    如果您有许多项目要进入列表,您可以利用初始化程序。下面以 myclass 构造函数为例,它以一个字符串和一个 int 为例。

    list<myclass> lst {{"one", 1},{"two", 2},{"three", 3}};
    

    如果这是一个需要使用指针的赋值,一定要使用new 而不是malloc 并且它是家庭来分配存储的,但请考虑这是最后的手段。

    首选是使用智能指针。其中最大的两个是unique_ptrshared_ptr

    list<unique_ptr<myclass>> lst;
    
    lst.push_back(unique_ptr<myclass>(new myclass()));
    

    或在 C++14 或更高版本中,

    lst.push_back(make_unique<myclass>());
    

    unique_ptr 从列表中移除时会自动销毁 myclass。

    但我认为这与直接包含 myclass 的列表相比没有任何优势,除非 myclass 是类层次结构的基类。如果您处于学习 C++ 的早期阶段,请在走这条路线之前先阅读和练习一些基础知识。

    list<shared_ptr<myclass>> lst;
    
    lst.push_back(shared_ptr<myclass>(new myclass()));
    

    使我的课程具有引用计数,可以与他人共享。当每个用户都释放了他们的 shared_ptr 时,myclass 将被销毁。这对于带有回调的系统非常有用。当回调触发时,回调对象将在那里,防止各种有趣的段错误。缺点是对象的生命周期是模糊的。何时销毁取决于未完成的 shared_ptrs。

    不允许对 shared_ptrs 进行循环引用,因为引用计数永远不会降为零。这里可能会内置一些非常狡猾的代码来提供帮助,但我不会指望它。反正程序设计不好。

    带有new 的原始指针。只是不要这样做。您有更好、更安全的选择。

    lst.push_back(new myclass());
    
    1. 如果我想从列表和程序存储空间中完全删除(释放)一个项目,我应该使用 pop 还是 remove 或 erase ?区别?

    remove 不存在列表。弹出,取决于你使用哪一个,要么删除firstlast 元素。如果列表表示队列或堆栈,请使用 pop。 erase 可以删除任何元素,只要你知道它在哪里。找到它可能需要搜索。

    使用存储对象list&lt;myclass&gt;,您可能无法取回任何内存。该列表可能会保存分配的 RAM,因此以后不必再次请求它。坦率地说,我不确定标准对列表的政策是什么。对于vectors,对象被销毁,但空间仍然分配,除非您手动强制调整大小。我相信 list 的行为方式相同,因为存在 resize 方法和文档的措辞。

    如果你有一个原始指针,你必须delete 它,然后从列表中删除它。您不能按其他顺序执行此操作,因为一旦从列表中删除指针就无法访问并且 RAM 会丢失。是的,您可以复制指针,然后将其从列表中删除,然后删除副本,但是为什么要付出额外的努力呢?我相信指针仍会在列表中分配,但将无法访问并等待重用。

    如果您使用 unique_ptr,则 unique_ptr 会为您处理处置。使用 shared_ptr,也会为您处理处置,但您不一定知道何时。 shared_ptr 的另一个副本可能存在,阻止销毁。

    1. 我应该在迭代列表时使用 operator delete 还是 .erase .remove 足以释放空间?

    在我对 2 的回答中已涵盖。使用指针,从列表中删除只会删除指向 myclass 的指针,而您没有指向 myclass 的指针,并且 RAM 会丢失。使用智能指针,myclass 会被智能指针销毁,无需进一步努力。

    但如果 R​​AM 被列表保留以供重复使用,您可能不会获得任何明显数量的 RAM。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      • 2023-01-22
      • 2021-08-08
      • 2020-05-25
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      相关资源
      最近更新 更多