向量中字符串的内存分配

Memory allocation for strings in vectors

本文关键字:内存 分配 字符串 向量      更新时间:2023-10-16

如果向量始终提供连续的内存存储,编译器如何为空 std::string 分配内存?

我有一个向量,我已经将许多类推送到 std:string 作为私有成员。然后,我将对向量的引用作为参数传递给另一个方法。

字符串的数据是否在堆中的其他位置引用自向量的连续数组?

std::string分配内存是微不足道的。

在内部,它将具有某种指针,指向将存储实际字符串数据的内存块。因此,为 std::string 分配内存只是为指针、size_t或其他东西分配空间的问题,也许还有几个原语。

例如,如果你有一个std::vector<std::string>,向量很容易为std::string分配空间,因为它们对于一些常量k只有k个字节。字符串数据将不参与此分配。

在这种情况下,内存中实际发生的情况的细节完全取决于您使用的特定 STL 实现。

话虽如此,我的印象是,在大多数实现中,向量和字符串都是用类似的东西实现的(非常简化):

template<typename T>
class vector
{
//...
private:
T* _data;
};
class string
{
private:
char _smallStringsBuffer[kSmallSize];
char* _bigStringsBuffer;
};

向量的数据根据容量在堆上动态分配(默认初始化时具有默认值,并在向向量添加元素时增长)。

字符串的数据静态分配给小字符串(依赖于实现的值"small"),然后在字符串变大时动态分配。出现这种情况的原因有很多,但主要是为了更有效地处理小字符串。

您描述的示例如下所示:

void MyFunction(const vector<string>& myVector)
{
// ...
}
int main()
{
vector<string> v = ...;
// ...
MyFunction(v);
// ...
return 0;
}

在这种特殊情况下,只有向量 v 的基本数据将在堆栈中,因为v._data数据将被分配到堆上。如果 v 的容量N,则堆中 v._data 的大小将为 sizeof(string) * N,其中字符串的大小是一个常量,取决于 kSmallSize * sizeof(char) + sizeof(char*),基于上面字符串的定义。

至于连续数据,只有当向量中收集的所有字符串的字符少于kSmallSize时,它们的数据才会在内存中"几乎"连续。

对于性能关键型代码来说,这是一个重要的考虑因素,但说实话,我认为大多数人不会在这种情况下依赖标准 STL 的向量和字符串,因为实现细节会随着时间的推移以及不同的平台和编译器而变化。此外,每当你的代码超出"快速"路径时,你不会注意到,除非延迟峰值很难控制。