【问题标题】:Questions About Vectors and Deleting Memory Associated With Them关于向量和删除与它们相关的内存的问题
【发布时间】:2016-08-23 00:23:45
【问题描述】:

几个月前,我使用 Vectors 编写了一个程序。我使用clear() 成员函数来“重置”向量,假设它不仅会清除元素中的项目并重置大小数据成员,而且还会将正在使用的内存归还给堆以前用它。好吧,我偶然发现了一篇关于向量的帖子,说这不是从向量中取回内存的正确方法,因为使用 clear() 不会这样做,但需要使用交换方法:

vector<MyClass>().swap(myVector);

我很好奇为什么我们必须调用交换来删除旧内存?我认为这更像是一种解决方法,因为我们正在使用交换,但正在发生其他事情。是否调用了析构函数?

最后一个问题,我现在读到的所有文章都说clear() 不会释放对象被“销毁”的内存。谁能澄清这是什么意思?我对普通话不熟悉。我假设如果一个对象被破坏了,它就会被清除,并且内存被归还给堆,但这是错误的,那么“破坏”这个词是指只擦除与每个元素相关的位吗?我不知道。任何帮助将不胜感激。谢谢。

【问题讨论】:

  • std::vector::clear() 应该触发向量中元素的析构函数。对于健全性检查,您可以在 MyClass 对象中放置一条打印语句以查看它的发生情况。
  • 你很可能误读了所读的内容。
  • 当你清除它们时,向量会保持它们的容量,因为它们假设你要向向量添加新元素。因此,保留内存比在添加内存时重新分配内存更有效。
  • 通常当你用完一个向量时,你会离开它被声明的范围,然后它将被完全销毁。如果确实需要重置,可以使用swap方法。
  • 需要区分vector本身使用的内存,以及vector中MyClass对象使用的内存。当你清除向量时,后面的对象被销毁并回收它们的内存,但不是向量本身(它在内部只是一个指针数组)。

标签: c++ vector


【解决方案1】:

要回答这个问题,您需要将vector 直接分配的内存与通过成员对象间接“拥有”的内存分开。例如,假设 MyClass 是一个占用 1000 个字节的对象,然后您使用 std::vector&lt;std::unique_ptr&lt;MyClass&gt;&gt;。然后,如果该向量有 10 个元素,则在 64 位系统上直接分配的内存通常接近 10*8=80 字节,而 unique_ptr 对象间接拥有 10*1000=10000 字节。

现在,如果您在向量上调用 clear(),则会在每个 unique_ptr 元素上调用析构函数,因此 10000 个间接拥有的字节被释放。但是,底层数组存储并没有被释放,所以仍然分配了向量直接拥有的 80 多个字节。 (此时,向量的 capacity() 至少为 10,但 size() 为 0。)如果您随后调用向量的析构函数,这将导致存储数组也被释放。

现在,如果你执行

std::vector<std::unique_ptr<MyClass>>().swap(v);

让我们分解它的作用:首先,创建一个临时向量对象,它没有分配数组,capacity() 为 0。现在,swap 将底层数组 v 转移到临时向量, 并将临时向量中的空数组或空数组交换为v。最后,在表达式的末尾,临时对象超出范围,因此调用了它的析构函数。这会导致调用以前属于v 的任何元素的析构函数,然后释放以前属于v 的底层数组存储。所以到最后v.capacity()为0,之前属于v的所有内存都被释放了,不管是v直接分配的还是通过存储的unique_ptr对象间接属于它的。

【讨论】:

  • @DanielSchepler,您的回答非常具体,非常感谢。我只有一个问题。因此调用交换函数将有效地释放与 clear() 释放(销毁对象)相同的内存并释放与向量本身关联的内存,因此如果用户要执行 clear(),然后进行交换,这将是多余的因为交换本身释放了两组记忆。它是否正确?我只是想确保我理解正确。似乎 swap 在释放内存时涵盖了两个基础,而 clear 仅涵盖了一个。
【解决方案2】:

vector 有一个名为 capacity 的关联数量,这意味着它已为那么多元素分配了足够的内存,即使它目前实际上不包含那么多元素。

如果在向量中添加或删除元素时未超出容量,则不会分配或释放内存;各个元素的构造函数和析构函数在已经分配的空间上运行。

clear() 函数不会改变容量。然而,vector::swap() 的通常实现也会交换向量的容量;因此与空向量交换将导致原始向量具有默认容量,该容量将很小甚至为零(取决于实现),因此应该释放内存。

从 C++11 开始,有一种正式的方法来减少容量,称为 shrink_to_fit()

请注意,C++ 标准实际上并不要求在减少容量后将内存释放给操作系统;这取决于您使用的库实现的作者和操作系统的组合。

【讨论】:

    猜你喜欢
    • 2010-12-10
    • 1970-01-01
    • 2023-03-04
    • 2012-06-28
    • 2010-12-29
    • 1970-01-01
    • 1970-01-01
    • 2011-10-08
    • 2016-03-14
    相关资源
    最近更新 更多