C++ 具有堆栈和动态分配的容器
是否有一个容器对少量元素使用本地缓冲区,并且仅当元素数量超过某个限制时才使用堆分配?与大多数C++ 具有堆栈和动态分配的容器,c++,optimization,stl,containers,C++,Optimization,Stl,Containers,是否有一个容器对少量元素使用本地缓冲区,并且仅当元素数量超过某个限制时才使用堆分配?与大多数std::string实现类似 背景 容器在以下(简化)上下文中使用: Foo-Foo;//一些数据 向量标记;//接收“标记”项目 //第一次通过:覆盖someList中的所有项目 对于每个(someList中的HandlerPtr h) { h->HandleFoo(foo);//foo可能在此处被标记或未标记 if(foo.taged()) 标记。推回(h); } 对于(自动itr=taged.r
std::string
实现类似
背景 容器在以下(简化)上下文中使用:
Foo-Foo;//一些数据
向量标记;//接收“标记”项目
//第一次通过:覆盖someList中的所有项目
对于每个(someList中的HandlerPtr h)
{
h->HandleFoo(foo);//foo可能在此处被标记或未标记
if(foo.taged())
标记。推回(h);
}
对于(自动itr=taged.rbegin();itr!=taged.end();++itr)
{
// ...
}
此代码部分具有较高的调用频率,但标记项的情况非常少见,someContainer
中的项数通常较低,但未绑定。我不能轻易地使用预先分配的“更全局”缓冲区。目标是避免频繁的分配
呼叫频率
- 通用:没有项目被标记。向量是好的
- 常见:只有少数项目中的一项被标记。导致我想要避免的高频率分配
- 非常罕见,但必须得到支持:someList在第一次通过时会增长,项目数量不可预测,但仍然很低
- 没有标准容器可以保证这种行为。但是,如果您能胜任,可以创建一个自定义的STL兼容分配器类,该类从小型堆栈缓冲区中提取用于小型分配的数据,并且仅当请求的分配大小超过堆栈缓冲区的大小时才执行堆分配。您可以插入自定义分配器类作为
std::vector
的第二个模板参数
有关创建自定义分配器的信息,请阅读。没有标准容器可以保证这种行为。但是,如果您能胜任,可以创建一个自定义的STL兼容分配器类,该类从小型堆栈缓冲区中提取用于小型分配的数据,并且仅当请求的分配大小超过堆栈缓冲区的大小时才执行堆分配。您可以插入自定义分配器类作为
std::vector
的第二个模板参数
有关创建自定义分配器的信息,您应该阅读。尽管不能保证这一点,但大多数
std::string
将实现小字符串优化
,就是这样(使用VC++10最多可存储8或16个字符)
我没有见过
std::string
将实现小字符串优化
,就是这样(使用VC++10,最多可存储8或16个字符)
我没有见过
std::vector
在至少插入一个元素之前不会分配任何内存。是否使用静态或堆栈分配?有关堆栈分配,请参见@nimrodn:stack allocation可能是我想要的更好的描述(固定标题)。i、 e.可以存储在容器实例中的有限数量的元素(无需额外分配),如果这还不够,则使用堆分配。std::vector
在至少插入一个元素之前不会分配任何内存。您也可以尝试.reserve()在向量中保留较小的空间,但“够了“大多数时候。如果向量的策略是从1开始,并且无论当前大小都使用相同的调整大小策略,那么这可能会避免重新分配。@Karl:常见的情况是容器将保持为空。保留将不利于此,因为它将始终分配动态内存。在C++0x中,这当然是解决方案,但是,如果我没有记错的话,C++03分配器不应保持未在分配器的所有实例之间共享的状态(也就是说,可能会要求相同类型的任何其他分配器销毁/取消分配,即使这两个实例完全不相关)。实际上,我认为应该可以这样做:)您也可以尝试。reserve()在向量中保留一定量的空间,虽然空间很小,但大多数情况下“足够”。如果向量的策略是从1开始,并且无论当前大小都使用相同的调整大小策略,那么这可能会避免重新分配。@Karl:常见的情况是容器将保持为空。保留将不利于此,因为它将始终分配动态内存。在C++0x中,这当然是解决方案,但是,如果我没有记错的话,C++03分配器不应保持未在分配器的所有实例之间共享的状态(也就是说,即使两个实例完全不相关,也可能会要求相同类型的任何其他分配器销毁/取消分配)。在实践中,我认为它应该可以工作:)向量的大小通常不会超过三个指针的大小。考虑到你还需要存储一些内务管理数据,这个空间能容纳多少数据?@客人我想这取决于你是否使用更高的空间
Foo foo; // some data
vector<HandlerPtr> tagged; // receives "tagged" items
// first pass: over all items in someList
for each(HandlerPtr h in someList)
{
h->HandleFoo(foo); // foo may become tagged or untagged here
if (foo.Tagged())
tagged.push_back(h);
}
for(auto itr=tagged.rbegin(); itr!=tagged.end(); ++itr)
{
// ...
}