为啥使用 std::vector 而不是 realloc? [关闭]
Posted
技术标签:
【中文标题】为啥使用 std::vector 而不是 realloc? [关闭]【英文标题】:Why use std::vector instead of realloc? [closed]为什么使用 std::vector 而不是 realloc? [关闭] 【发布时间】:2020-12-04 01:59:42 【问题描述】:这里,在this question 中,声明在c++ 中没有类似realloc
的运算符或函数。如果您想调整数组大小,只需 std::vector
即可。我什至看到 Stroustrup 说过同样的话here。
我相信实施一个并不难。应该有不实施的理由。答案只说使用std::vector
,但没有说为什么没有实现。
没有实现realloc
-like 运算符或函数而是更喜欢使用std::vector
的原因是什么?
【问题讨论】:
vector
随时可用、功能齐全且经过良好测试。为什么要重新发明***?
这能回答你的问题吗? How do you 'realloc' in C++?
“我相信实现一个并不难。” — 在重新分配期间,您将如何处理 non-trivially-copyable 类型?跨度>
@StackExchange123 为什么要这样复制std::vector
的功能?请注意,这并不像您写的那么容易。您需要关心异常安全,类型可以具有复制/非抛出移动/抛出移动构造函数,您需要分别处理这些情况,等等。
@d4rk4ng31 -- 我不知道你所说的“微不足道”的内存块是什么意思。在这一切之下,它只是原始内存,realloc
有时可以扩展内存块,而new
和delete
永远不能。有几次建议添加一个renew
运算符,它可以做同样的事情:如果他们的房间在适当的位置扩展一个内存块,然后初始化占用新添加内存的对象。
【参考方案1】:
好吧,因为其他答案已经很好地解释了使用向量的原因,我将简单地详细说明为什么 realloc
没有实现。为此,您需要查看realloc
的实际作用。它通过智能地使用malloc()
和free()
来增加内存的大小。你需要明白,虽然它看起来只是增加了大小,但实际上并没有增加大小,而是分配了另一个具有所需大小的内存块(这解释了名称realloc
)。
看看下面几行:
int* iarr = (int*)malloc(sizeof(iarr)*5);
iarr = (int*)realloc(6,sizeof(iarr)); //this is completely discouraged
//what you're supposed to do here is:
int* iarr2 = (int*)realloc(iarr,1 + sizeof(iarr)); //copies the old data to new block implicitly
//this not only saves the previous state, but also allows you to check if realloc succeeded
在 C++ 中,这可以(如果必须)通过以下方式实现:
int* iarr = new int[5];
int* iarr2 = new int[6];
for(int i = 0; i < 5; i++)
iarr2[i] = iarr[i];
delete[] iarr;
realloc
的唯一用途是增加内存容量;由于C arrays
没有自动这样做,他们必须提供一种机制来这样做;这已在大多数 containers
中隐式实现,因此首先使用 realloc
的原因没有实际意义。
【讨论】:
我相信realloc
会尽可能扩展分配的内存。如果没有,则使用free
和malloc
。
@StackExchange123 但是如果它不能扩展,那么realloc()
将原始数据从旧分配复制到新分配,这仅适用于可简单复制的类型。例如。 realloc()
在 std::string
的数组上是未定义的行为,除非分配可以在没有副本的情况下扩展。我猜std::vector
可以 SFINAE 在 std::is_trivial
上重新分配它,但是它需要使用 malloc()
和 free()
而不是 C++ 分配器。
@cdhowie,另外,它与 new 和 delete 不兼容。我认为真正的问题是,why is realloc not compatible with new and delete?
@StackExchange123,没那么容易
@StackExchange123 可能是因为vector的开销很小,而且它的效用远远超过了这个开销。 :) realloc 没有 C++ 标准的安全版本,因为人们宁愿使用向量也不愿使用类似向量的东西。【参考方案2】:
没有实现
realloc
-like 运算符或函数而是更喜欢使用std::vector
的原因是什么?
节省时间。不要在你自己的代码中追逐一个早已解决的问题。惯用的 C++ 和可读性。轻松快速地获得问题的答案。通过分配器自定义realloc
部分。
我相信实现一个并不难
这在很大程度上取决于您需要从您打算编写的模板中获得什么。对于通用的std::vector
-like ,请查看源代码(libcxx
的 3400 行 vector
标头为 here)。我敢打赌你会修正你对这种结构的低复杂性的最初假设。
【讨论】:
【参考方案3】:realloc
期望在当前分配之后可能有足够的可用空间,这与现代分配器和现代程序不太匹配。
(还有更多的分配正在进行,许多分配大小进入该大小的专用池,并且堆在程序中的所有线程之间共享。)
在大多数情况下,realloc
必须将内容移动到全新的分配中,就像 vector 一样。但与vector<T>
不同,realloc
不知道如何移动T
类型的元素,它只知道如何复制纯数据。
【讨论】:
64 位系统有大量的虚拟地址空间,大的分配通常会从操作系统获得一些新的页面(例如通过mmap
)。一些操作系统甚至有像 Linux 的 mremap(MREMAP_MAYMOVE)
这样的系统调用,它是一个页面粒度 realloc,即使在当前位置没有空间让这个映射增长,也可以避免复制。 (只需更新页表,以便将相同的物理页面映射到新的虚拟地址,最后有额外的空间)。不值得因为小尺寸而被 TLB 击落,但值得几 GiB。【参考方案4】:
有几个优点。
Vector 会跟踪其大小和容量,这意味着您不必自己执行此操作。 因为当前大小是矢量对象本身的一部分,所以您可以传递一个矢量(通过引用或通过值)而不需要额外的大小参数。这在返回向量时特别有用,因为调用者不需要通过某个边通道接收大小。 在重新分配时,向量将添加比仅添加请求添加的元素所需的容量更多的容量。这听起来很浪费,但可以节省时间,因为需要的重新分配更少。 Vector 管理自己的内存;使用向量可以让您专注于程序中更有趣的部分,而不是管理内存的细节,这些细节相对乏味且难以完全正确。 Vector 支持数组本身不支持的许多操作,例如从中间移除元素和制作整个向量的副本。【讨论】:
以上是关于为啥使用 std::vector 而不是 realloc? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 'std::vector<int> b2;'创建一个 1 元素向量,而不是 2 元素向量?
为啥使用指针的 STL 算法比 std::vector 迭代器快得多?
为啥 std::vector 需要 is_trivial 进行按位移动,而不仅仅是 is_trivially_copyable?