未使用的 STL 容器是否分配内存
Does an unused STL container allocate memory?
给定代码:
class Foo {
std::vector<int> items;
std::map<int, int> dictionary;
};
如果上面的向量或映射中没有添加任何内容,是否仍会分配缓冲区内存块? (换句话说,缓冲区分配是否总是在容器创建期间发生,或者是否可以推迟到调用 push_back 等函数?
是否有处理初始 STL 容器缓冲区分配计时的标准,或者是否允许该行为在 STL 容器和编译器之间变化?
注意:这个问题不是关于此类容器会增加类 Foo 大小的额外字节。
(此问题的一个强调分配大小的相关子集是向量的初始容量(以 C++为单位)。
C++引用 对于 C++17,默认构造函数noexcept
,如果分配器构造noexcept
。所以这取决于使用的分配器。在VS 2015中,标准构造函数是noexcept
。
澄清:这意味着如果分配器没有noexcept
则不会分配内存块。
对于你的第二个问题:相同的引用,它是O(1)。
Standard 对此没有任何说明,但我专门研究的实现会为 std::vector
做一些预置,并且不会为std::map
预先分配任何东西。
这实际上曾经对我打击很大,当我拥有一个巨大的容器时,其中元素具有微小的 - 不超过 10 个元素,大多数条目都有 0 大小的向量 - 向量。此实现中的默认矢量容量为 32,而"32 * sizeof(vector_element) * number_of_elements"恰好非常大。
如前所述,这没有很好的定义。但是,您可以对其进行测试。
例如使用 gcc/linux。制作一个简单的程序,用-O0 -g
编译并在gdb中运行它。然后
break main
run
break malloc
cont
现在只需在每个 malloc 上运行backtrace
,您将看到动态分配。使用我的 gcc 5.3.0,两个空容器都不会分配堆内存,这是在第一个 push_back
/operator[]
上完成的。
当然,您应该使用首选的调试器并中断分配器底层函数,如果这不是gdb
/malloc
。
现在,如果您考虑这两种情况。在这种情况下,预先分配内存是否有意义?
std::vector<int> foo;
foo.push_back(13);
好吧,从技术上讲,您可能会保存nullptr
的检查,但是使用将向量实现为3指针的常用方法,不需要额外的检查。
但请考虑
std::vector<int> foo;
foo.reserve(100);
在这种情况下,预先分配将不利于性能。
我找不到为地图等树结构进行预分配的论据。
请记住,这是一个非常具体的优化。只有在有充分理由的情况下才能对此进行优化(基准测试!
注意:您可能想阅读有关小字符串优化的信息,这是一种非常常见的技术,相关但不同。
- 如果上面的向量或地图中没有添加任何内容,是否仍会为潜在条目分配内存块?(换句话说,条目分配是否总是在容器创建期间发生,或者是否可以推迟到调用 push_back 等函数?
这是可能发生的,是的。它实际上是容器实现的细节,未在标准中指定。
- 是否有处理初始 STL 容器分配时间的标准,或者是否允许该行为在 STL 容器和编译器之间变化?
例如,您可以使用成员的std::unique_ptr
来延迟创建,并通过调用 getter 函数来创建它们。
,Microsoft的 STL 实现目前确实在默认构造函数中分配了 std::map
和 std::set
。Godbolt 示例 - 请注意程序集输出第 8 行对 operator new
的调用。
是的,这绝对会影响性能。我只是在分析了一些神秘的慢代码之后才意识到这一点,当时事实证明,具有很少使用的map
成员的类的默认构造函数正在主导相关循环的运行时。
如果像我一样,你对这个实现决定并不完全兴奋,我会指出 Boost.Container 的对应方确实保证了零分配默认构造。
- 我在二维向量中是否正确分配了内存
- 当一个新对象被分配到它的地址时,对象是否必须被销毁
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 是否可以使用其他变量为变量分配值,而无需在 C++ 中更改其值?
- 堆分配的对象是否存在永不为空的唯一所有者?
- 新分配指向函数的指针是否合法?
- 在对象指针上调用 Delete 是否会递归删除其动态分配的成员
- 是否可以使用分配器对象来释放另一个分配器分配的内存?
- 释放动态分配的内存时是否需要执行此额外步骤
- std::initializer_list 堆是否分配内存?
- 迭代器是否分配内存(如指针)?
- C 检查值是否分配给了类的成员
- 内存管理 - 添加小部件是否分配父级
- 一般来说,如何找出客户端是否分配了静态Ip或是dhcp客户端
- 未使用的 STL 容器是否分配内存
- 移动是否分配了 std::fstream 关闭原始流
- 我如何知道是否分配了内存插槽
- 要声明指针变量,内存是否分配给指针的名称或指针的地址?
- 宏是否分配内存?
- 是否有一种方法来判断是否分配了内存缓冲区并且必须删除