【问题标题】:Using STL Allocator with STL Vectors将 STL 分配器与 STL 向量一起使用
【发布时间】:2011-01-08 00:47:14
【问题描述】:

这是基本问题。有一个我依赖的 API,其方法使用以下语法:

void foo_api (std::vector<type>& ref_to_my_populated_vector);

有问题的代码区域是性能密集型的,我想避免使用堆来分配内存。因此,我创建了一个自定义分配器,它为堆栈上的向量分配所需的内存。所以,我现在可以将向量定义为:

// Create the stack allocator, with room for 100 elements
my_stack_allocator<type, 100> my_allocator;

// Create the vector, specifying our stack allocator to use
std::vector<type, my_stack_allocator> my_vec(my_allocator);

这一切都很好。与标准向量相比,使用堆栈分配向量的性能测试显示性能大约快 4 倍。问题是,我不能调用 foo_api!所以...

foo_api(my_vec); // Results in an error due to incompatible types.
// Can't convert std::vector<type> to std::vector<type, allocator>

有解决办法吗?

【问题讨论】:

  • 一般来说,在堆栈上分配数据没有安全和理智的方法。不要那样做,它迟早会坏掉的。简单地调用reserve() 来确保一次性分配内存怎么样?或者,如果您想要堆栈中的所有内容,请使用固定大小的数组
  • std::vector&lt;type, my_stack_allocator&gt; 应该是std::vector&lt;type, my_stack_allocator&lt;type, 100&gt;,是吗? typedef 在这里会有所帮助。
  • 没错 GMan -- 抱歉 :-/ 它非常安全。事实上,它已经完成了:src.chromium.org/viewvc/chrome/trunk/src/base/stack_container.h
  • @Andrew:太糟糕了。因为如果你能做到template&lt;typename Iter&gt; void foo_api(Iter begin, Iter end); 它会很好而且通用,并且可以与任何容器一起使用。
  • 或者template &lt;typename Sequence&gt; void foo_api(Sequence &amp;ref);,这样就不用过多修改foo_api的代码了。这取决于它使用的向量的成员函数。 foo_api 可能添加/删除任意元素,在这种情况下,使用迭代器编写 API 的唯一方法是复制和修改。

标签: c++ oop stl memory-management visual-c++


【解决方案1】:

您必须按照函数的预期使用默认分配器。你有两种不同的类型,这是没有办法的。

只需在对向量进行操作之前调用 reserve 即可消除内存分配。

想想可能发生的坏事。该函数可能会获取您的向量并开始添加更多元素。很快,您可能会溢出已分配的堆栈空间;哎呀!

如果您真的关心性能,更好的方法是将operator new 和kin 替换为自定义内存管理器。我已经这样做了,分配可以大大改善。对我来说,分配大小为 512 或更小的大小大约是 4 次操作(移动几个指针);我使用了池分配器)

【讨论】:

  • 分配器的编写方式是,如果请求的内存多于堆栈上保留的内存,它将求助于堆。在我看来,STL 处理不了这种场景,实在是太可悲了。似乎如果分配器由几个函数指针和一段用户定义的数据组成,这种事情是可能的。
  • foo_api() 并不真正关心分配器。反正不是直接的。但是向量可以。您遇到的问题不是 STL 缺陷的证据(但它确实有这些缺陷),而是 foo_api() 的界面中的缺陷。
  • @Andrew:混合接口是毁灭性的! 分配器是类型的一部分。当填充向量时使用一个接口,然后函数使用单独的接口释放它时会发生什么?未定义的行为。 C++ 的方式是将容器与其算法分离;使用迭代器。
  • 为什么要让世界上的每个向量都成为更大的函数指针,甚至可能更慢,以便像 foo_api 这样的坏接口可以支持像您的自定义分配器这样的不寻常用例? foo_api 坚持认为输入必须是使用默认分配器的向量。如果 foo_api 想要支持其他向量,它可以通过作为模板并将分配器作为模板参数来实现。或者它可以使用 C++ 方式并采用迭代器参数,而不是任何类型的向量。它不希望你传递你想要传递给它的对象——这不是 STL 的缺陷。
  • @Andrew:“如果 API 的设计者按照您所描述的那样做,那么一切都会是模板!”呃,猜猜标准库和 boost 主要是什么......模板!泛型编程是实现泛型算法的最佳方式之一。您传递迭代器的方式与所有基于迭代器的算法的工作方式相同。它将采用 templated type 作为迭代器,不可能有类型不匹配。是的,函数指针不能内联,因此它们更慢。显然,现在我们不同意更好这个词。动态内存来自堆;那是newdelete
猜你喜欢
  • 2013-05-30
  • 1970-01-01
  • 2020-03-01
  • 2011-09-11
  • 1970-01-01
  • 2012-03-16
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多