如何在构建时为 std::vector 保留内存?
How do I reserve memory for a std::vector at construction time?
通常我会在构建 std::vector
后立即调用 reserve
。这通常不会导致 std::vector
的现有堆分配被破坏并替换为新分配吗?有没有办法在构造时保留内存而不是分配堆 space 然后立即销毁它?或者 std::vector
中是否有实施技巧来确保这不是问题?
可用的构造函数似乎只能用于用值填充 std::vector
,而不是显式保留 space。
您的问题基于一个错误的前提,即默认构造的 std::vector<T>
将执行 [零长度] 分配。
它确实没有理由这样做。一个新的向量应该有容量零(虽然这是理智的要求,而不是标准)。
因此,您的目标已经内在地满足了。
坦率地说,标准库并不那么愚蠢。
如果您在编译时知道元素的数量,您可以使用这些元素对向量进行列表初始化:
class MyClass
{
int x, y, z;
std::vector<int> v;
public:
MyClass(int X, int Y, int Z) : x(X), y(Y), z(Z), v{x, y, z}
{}
};
但这不是很好维护。还有更高级的技术,例如您可以使 std::vector
使用的自定义分配器可以从预分配的内存池中获取内存,例如:我怀疑您是否真的需要它。现代实现可以轻松优化如此简单的问题。
对象 std::vector
及其元素数组不存在于同一个连续的内存块中,否则每次调整数组大小时其地址都会发生变化,从而无法保持可靠的引用它。该对象的主体仅包含控制变量和指向实际数组的指针,它将与其他局部变量一起在堆栈中实例化(假设您将其用作局部变量)。而此时数组将是空的,并且可能由指向 nullptr
的指针表示。因此,无论您 reserve
在构建时还是在构建后立即进行,都不会发生重大优化。
如果您想要立即保留静态大小的 std::vector
,您可以只使用常规 C 数组而不是 std::vector
。只要确保它适合堆栈即可。
原因可能有点讽刺,我们 运行 没有函数签名。
需求来自使用场景,我们确切地知道要将多少元素保存到 vector 中,但我们真的不喜欢 n-duplicated elements 构造函数:
std::vector( size_type count, const T& value = T())
不幸的是签名被上面的构造函数占用了。任何其他可能的签名都可能导致问题。例如
vector(size_type count, size_type reserve_count)
将与 T(size_type)
.
向量的上述 n 重复元素构造函数冲突
vector(size_type count, const T& value = T(), size_type reserve_count)
是一个可能的解决方案,但它太长而且仍然很无聊。我们需要构造一个在调用 auto v = vector<T>(0, T(), reserve_count)
时从不使用的默认值
其他可行方案:
提供类似make_pair/make_unique的功能。
定义一个从Allocator派生的Reserver,所以我们可以像
一样使用constructor vector(const Allocator& alloc)
auto v = vector<Type>(new Reserver(reserve_count));
通常我会在构建 std::vector
后立即调用 reserve
。这通常不会导致 std::vector
的现有堆分配被破坏并替换为新分配吗?有没有办法在构造时保留内存而不是分配堆 space 然后立即销毁它?或者 std::vector
中是否有实施技巧来确保这不是问题?
可用的构造函数似乎只能用于用值填充 std::vector
,而不是显式保留 space。
您的问题基于一个错误的前提,即默认构造的 std::vector<T>
将执行 [零长度] 分配。
它确实没有理由这样做。一个新的向量应该有容量零(虽然这是理智的要求,而不是标准)。
因此,您的目标已经内在地满足了。
坦率地说,标准库并不那么愚蠢。
如果您在编译时知道元素的数量,您可以使用这些元素对向量进行列表初始化:
class MyClass
{
int x, y, z;
std::vector<int> v;
public:
MyClass(int X, int Y, int Z) : x(X), y(Y), z(Z), v{x, y, z}
{}
};
但这不是很好维护。还有更高级的技术,例如您可以使 std::vector
使用的自定义分配器可以从预分配的内存池中获取内存,例如:我怀疑您是否真的需要它。现代实现可以轻松优化如此简单的问题。
对象 std::vector
及其元素数组不存在于同一个连续的内存块中,否则每次调整数组大小时其地址都会发生变化,从而无法保持可靠的引用它。该对象的主体仅包含控制变量和指向实际数组的指针,它将与其他局部变量一起在堆栈中实例化(假设您将其用作局部变量)。而此时数组将是空的,并且可能由指向 nullptr
的指针表示。因此,无论您 reserve
在构建时还是在构建后立即进行,都不会发生重大优化。
如果您想要立即保留静态大小的 std::vector
,您可以只使用常规 C 数组而不是 std::vector
。只要确保它适合堆栈即可。
原因可能有点讽刺,我们 运行 没有函数签名。
需求来自使用场景,我们确切地知道要将多少元素保存到 vector 中,但我们真的不喜欢 n-duplicated elements 构造函数:
std::vector( size_type count, const T& value = T())
不幸的是签名被上面的构造函数占用了。任何其他可能的签名都可能导致问题。例如
vector(size_type count, size_type reserve_count)
将与T(size_type)
. 向量的上述 n 重复元素构造函数冲突
vector(size_type count, const T& value = T(), size_type reserve_count)
是一个可能的解决方案,但它太长而且仍然很无聊。我们需要构造一个在调用auto v = vector<T>(0, T(), reserve_count)
时从不使用的默认值
其他可行方案:
提供类似make_pair/make_unique的功能。
定义一个从Allocator派生的Reserver,所以我们可以像
一样使用constructor vector(const Allocator& alloc)
auto v = vector<Type>(new Reserver(reserve_count));