假设我有std::vector
const std::string
s。
std::vector<const std::string> strs;
现在,这里的默认行为是实际的字符串容器可以分配在堆上的任何位置,这在迭代包含的字符串时几乎禁用了任何数据预取。
strs.push_back("Foo"); // allocates char block on heap
strs.push_back("Boo"); // allocates char block on heap
但是,由于字符串是“const”,我希望char块连续分配或彼此接近(如果可能),以便在迭代字符串时获得最有效的缓存行为。
有没有办法实现这种行为?
答案 0 :(得分:4)
您需要一个称为内存区域分配器的自定义分配器。你可以在维基百科或谷歌上查看更多信息,但基本思路类似于硬件堆栈 - 分配一个大块,然后简单地增加指针以将其标记为已使用。它可以非常快速地提供许多连续请求,但不能处理释放和分配 - 所有释放都是立即完成的。
答案 1 :(得分:1)
如果真的那么简单 - 推送永远不会改变的字符串,就很容易编写自己的分配器。分配大块内存,将指针free
设置为块中的偏移量0。当您需要将新字符串strncpy
存储到free
并使用free
增加strlen
时。跟踪内存块的结束并在需要时分配另一个块。
答案 2 :(得分:1)
不是。
std::string
不是POD,它不会将其内容保留在“对象内”。更重要的是 - 它甚至不需要将其内容存储在单个内存块中。
同样,std::vector
(因为所有数组)需要其内容为一种类型(=相等大小),因此您不能创建不同长度的字符串的“文字”数组。
您最好的方法是假设长度并使用std::vector<std::array<char, N> >
如果你需要非常不同的长度,那么对于数据而言,另一种选择只是std::vector<char>
加上连续字符串开始的索引的std::vector<unsigned>
。
为字符串滚动自己的分配器是一个诱人的想法,您可以将其基于std::vector<char>
,然后在其上汇总您自己的std::basic_string
,然后汇总这些。
请注意,您实际上非常依赖于特定的std::string
实施。有些具有N个字符的内部缓冲区,并且只有在字符串长度大于缓冲区时才从外部分配内存。如果你的实现就是这种情况,你仍然不会为整个字符串缓冲区获得连续的内存。
基于这个理由,我得出结论,使用std::string
您通常无法完成您想要的任务(除非您依赖于特定的STL实现)并且您需要提供另一个字符串实现以满足您的需求
答案 3 :(得分:1)
自定义分配器很棒,但为什么不将所有字符串存储在单个std::vector<char>
或std::string
中,并通过偏移量访问原始字符串?
简单有效。
答案 4 :(得分:0)
您始终可以编写一个私有分配器(std::vector
的第二个模板参数),它将从连续池中分配所有字符串。 同样您可以使用std::basic_string
代替std::string
(这是std::basic_string
的私有案例),这允许类似地指定您自己的分配器。一般来说,我会说它是一个“过早优化”的情况,但我相信你已经测量过,并且在这里看到了性能上升......我相信付出的代价会浪费一些内存。
答案 5 :(得分:-1)
保证向量是连续的内存并且是 可与阵列互操作。它不是一个单一的链表。
“邻接实际上是向量抽象的一部分。它非常重要,实际上,修改了C ++ 03标准以明确添加保证。”
来源:http://herbsutter.com/2008/04/07/cringe-not-vectors-are-guaranteed-to-be-contiguous/
使用reserve()
强制它是连续的而不是重新分配。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
// create empty vector for strings
vector<const string> sentence;
// reserve memory for five elements to avoid reallocation
sentence.reserve(5);
// append some elements
sentence.push_back("Hello,");
sentence.push_back("how");
sentence.push_back("are");
sentence.push_back("you");
sentence.push_back("?");
// print elements separated with spaces
copy (sentence.begin(), sentence.end(),
ostream_iterator<string>(cout," "));
cout << endl;
return 0;
}