创建模板类会产生主要瓶颈

时间:2011-12-15 08:20:39

标签: c++ templates vector

我正在尝试编写一个科学的图形库,它可以工作,但我有一些性能问题。在创建图形时,我使用节点的模板类,并执行类似

的操作
for(unsigned int i = 0; i < l_NodeCount; ++i) 
                m_NodeList.push_back(Node<T>(m_NodeCounter++));

即使在节点类的构造函数中几乎没有任何事情发生(一些变量被赋值),这部分是我程序的一个主要瓶颈(当我使用超过一百万个节点时),特别是在调试模式下,它变得太过分了根本无法运行。

是否有更好的方法可以同时创建所有这些模板类而无需每次都调用构造函数,或者我是否必须在没有模板的情况下重写它?

4 个答案:

答案 0 :(得分:4)

如果构造函数几乎没有做任何事情,正如你所说,瓶颈很可能是新内存的分配。向量动态增长,每次内存耗尽时,它将保留新内存并复制所有数据。当添加大量对象时,这可能非常频繁地发生,并且变得非常昂贵。这可以通过调用

来避免
m_NodeList.reserve(l_NodeCount);

通过此调用,向量将分配足够的内存来保存l_NodeCount个对象,并且在批量添加元素时不会有任何昂贵的重新分配。

答案 1 :(得分:3)

您的代码中会发生一些事情:

  • 当您向向量添加元素时,它偶尔会调整内部数组的大小,这涉及将所有现有元素复制到新数组
  • 为每个元素调用构造函数

构造函数调用是不可避免的。你创建了一百万个元素,你有一百万个构造函数调用。你可以改变的是构造函数的作用。

添加元素显然是不可避免的,但可以避免复制/调整 。最初在向量上调用reserve,为所有节点保留足够的空间。

根据您的编译器,优化设置和其他标志,编译器可能会执行大量不必要的边界检查和调试检查。

  • 您可以为编译器(VS2005 / 2008上的_SECURE_SCL=0,VS2010中的_ITERATOR_DEBUG_LEVEL=0禁用此功能。我相信它在GCC中默认关闭,并且不了解其他编译器。)
  • 或者,您可以重写循环以最小化需要执行的调试检查的数量。使用标准库算法而不是原始循环允许库跳过大多数检查(通常,然后在开始和结束迭代器上执行边界检查,而不是在中间迭代上执行,而在普通循环中,每次解除引用迭代器时都会完成)

答案 2 :(得分:1)

我想说,你的瓶颈不是一个与运行时无关的模板类,而是在编译时处理,但是在vector容器中添加一个元素(你的标签中有“vector”)题)。您正在使用push_back执行大量分配。尝试立即分配所需的总内存,然后填充元素。

答案 3 :(得分:0)

你可以避免模板购买对象的(void *)列表。并在以后投下它们 但是......如果您希望拥有1,000,000个节点类实例。你必须调用1,000,000个节点构造函数。