Not*_*ist 77 c++ memory-management stl vector
什么是capacity()的std::vector这是使用默认constuctor产生的?我知道这size()是零.我们可以声明默认构造的向量不会调用堆内存分配吗?
这样就可以使用单个分配创建一个具有任意保留的数组,例如std::vector<int> iv; iv.reserve(2345);.让我们说出于某种原因,我不想size()在2345年开始.
例如,在Linux上(g ++ 4.4.5,内核2.6.32 amd64)
#include <iostream>
#include <vector>
int main()
{
using namespace std;
cout << vector<int>().capacity() << "," << vector<int>(10).capacity() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
印刷0,10.这是规则,还是STL供应商依赖?
Mar*_*som 61
标准没有指定capacity容器的首字母应该是什么,所以你依赖于实现.一个常见的实现将启动容量为零,但不能保证.另一方面,没有办法改善你std::vector<int> iv; iv.reserve(2345);坚持下去的策略.
met*_*sis 23
std :: vector的存储实现差异很大,但我遇到的所有实现都是从0开始.
以下代码:
#include <iostream>
#include <vector>
int main()
{
using namespace std;
vector<int> normal;
cout << normal.capacity() << endl;
for (unsigned int loop = 0; loop != 10; ++loop)
{
normal.push_back(1);
cout << normal.capacity() << endl;
}
std::cin.get();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出以下输出:
0
1
2
4
4
8
8
8
8
16
16
Run Code Online (Sandbox Code Playgroud)
根据GCC 5.1和:
0
1
2
3
4
6
6
9
9
9
13
Run Code Online (Sandbox Code Playgroud)
根据MSVC 2013.
这是一个老问题,这里的所有答案都正确解释了标准的观点以及如何通过使用 ; 以可移植的方式获得初始容量std::vector::reserve。
不过,我将解释为什么任何 STL 实现在构造对象时分配内存都是没有意义的std::vector<T>;
std::vector<T>不完整的类型;
std::vector<T>在 C++17 之前,如果 的定义T在实例化时仍然未知,则构造 a 是未定义的行为。然而,这个限制在 C++17 中得到了放松。
为了有效地为对象分配内存,您需要知道它的大小。从 C++17 及更高版本开始,您的客户可能会遇到您的std::vector<T>类不知道T. 内存分配特性依赖于类型完整性是否有意义?
Unwanted Memory allocations
很多很多时候,您需要在软件中对图形进行建模。(树是图);您很可能将其建模为:
class Node {
....
std::vector<Node> children; //or std::vector< *some pointer type* > children;
....
};
Run Code Online (Sandbox Code Playgroud)
现在想一下,想象一下如果您有很多终端节点。如果您的 STL 实现只是为了在children.
这只是一个例子,大家可以想到更多......
小智 6
据我了解的标准(尽管我实际上不能命名参考),容器实例化和内存分配出于有充分的理由被有意地分离了。因此,您有不同的,单独的要求
constructor 创建容器本身reserve() 预分配一个适当的大内存块以容纳至少(!)个给定数量的对象这很有道理。存在的唯一权利reserve()是使您有机会在增长向量时围绕可能昂贵的重新分配进行编码。为了有用,您必须知道要存储的对象数量,或者至少需要能够进行有根据的猜测。如果不这样做,则最好远离,reserve()因为您将更改内存浪费的重新分配。
所以放在一起:
reserve()并且不必在同一构造位置(可以/当然应该稍后,在您知道要适应的大小之后)reserve(),不是吗?push_back()-如果尚未明确分配by之前的代码reserve()。只有在不被分配构造函数干扰的情况下,所有这一切才能发挥全部作用和优势。对于常见情况,您有合理的默认值,可以根据需要将其替换为reserve()(和shrink_to_fit())。因此,即使标准没有明确声明,对于所有当前的实现,我都可以肯定地假设一个新构造的向量没有预先分配是一个相当安全的选择。
作为对其他答案的一点补充,我发现在调试条件下使用 Visual Studio 运行时,即使容量从零开始,默认构造的向量仍会在堆上分配。
特别是如果 _ITERATOR_DEBUG_LEVEL != 0 那么 vector 将分配一些空间来帮助迭代器检查。
https://docs.microsoft.com/en-gb/cpp/standard-library/iterator-debug-level
我只是觉得这有点烦人,因为我当时使用的是自定义分配器,并没有期待额外的分配。