C ++枚举使用的速度比整数慢吗?

时间:2011-01-31 14:08:36

标签: c++ enums profiling performance

这真的是一个简单的问题:

我正在编写Go程序。我应该使用QVector<int>QVector<Player>

代表董事会
enum Player
{
    EMPTY = 0,
    BLACK = 1,
    WHITE = 2
};

我想当然,使用Player而不是整数将会更慢。但我想知道还有多少,因为我相信使用enum是更好的编码。

我做了一些关于分配和比较玩家的测试(而不是int

QVector<int> vec;
vec.resize(10000000);
int size = vec.size();


for(int i =0; i<size; ++i)
{
    vec[i] = 0;
}


for(int i =0; i<size; ++i)
{
    bool b = (vec[i] == 1);
}


QVector<Player> vec2;
vec2.resize(10000000);
int size = vec2.size();


for(int i =0; i<size; ++i)
{
    vec2[i] = EMPTY;
}


for(int i =0; i<size; ++i)
{
    bool b = (vec2[i] == BLACK);
}

基本上,它只慢了10%。在继续之前还有什么我应该知道的吗?

谢谢!

编辑:10%的差异不是我的想象力,它似乎是Qt和QVector特有的。当我使用std :: vector时,速度是相同的

7 个答案:

答案 0 :(得分:80)

枚举在编译时完全解析(枚举常量为整数文字,枚举变量为整数变量),使用它们没有速度损失。

通常,平均枚举的基础类型不会大于int(除非你输入非常大的常量);事实上,§7.2¶5明确地说:

  

枚举的基础类型是一个整数类型,可以表示枚举中定义的所有枚举器值。它是实现定义的,其中整数类型用作枚举 的基础类型,但基础类型不得大于int 除非枚举数的值不适合intunsigned int

你应该在适当的时候使用枚举,因为它们通常会使代码更容易阅读和维护(你有没有试过调试一个充满“幻数”的程序?:S)。

至于你的结果:可能你的测试方法没有考虑你在“普通”机器上运行代码时的正常速度波动 1 ;您是否尝试过多次(100+次)运行测试并计算您的时间的平均值和标准差?结果应该是兼容的:平均值之间的差异不应大于两个标准差的RSS 2 的1或2倍(假设,通常情况下,波动的高斯分布)。

您可以做的另一项检查是比较生成的汇编代码(使用g ++,您可以使用-S开关获取它。)


  1. 在“普通”PC上,由于其他任务正在运行,缓存/ RAM / VM状态,您有一些不确定的波动......
  2. Root Sum Squared,平方标准偏差之和的平方根。

答案 1 :(得分:44)

通常,使用枚举应该对性能完全没有区别。你是怎么测试的?

我自己只是进行了测试。差异是纯粹的噪音。

刚才,我将这两个版本编译成汇编程序。以下是各自的主要功能:

INT

LFB1778:
        pushl   %ebp
LCFI11:
        movl    %esp, %ebp
LCFI12:
        subl    $8, %esp
LCFI13:
        movl    $65535, %edx
        movl    $1, %eax
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        ret

播放器

LFB1774:
        pushl   %ebp
LCFI10:
        movl    %esp, %ebp
LCFI11:
        subl    $8, %esp
LCFI12:
        movl    $65535, %edx
        movl    $1, %eax
        call    __Z41__static_initialization_and_destruction_0ii
        leave
        ret

基于微基准测试的任何关于性能的陈述是有害的。有太多外来因素扭曲了数据。

答案 2 :(得分:17)

枚举应该不慢。它们被实现为整数。

答案 3 :(得分:3)

如果您使用Visual Studio,您可以创建一个简单的项目

     a=Player::EMPTY;

如果右键单击“转到反汇编”,代码将为

mov         dword ptr [a],0

因此编译器会替换枚举的值,通常它不会产生任何开销。

答案 4 :(得分:3)

好吧,我做了一些测试,整数和枚举形式没有太大区别。我还添加了一个char形式,它的速度一直快6%(这并不奇怪,因为它使用的内存较少)。然后我只使用了一个char数组而不是一个向量,这个速度提高了300%!既然我们没有得到QVector是什么,它可能是一个数组的包装器,而不是我用过的std :: vector。

这是我使用的代码,使用Dev Studio 2005中的标准发行版选项进行编译。请注意,由于问题中的代码可以优化为零,我已经更改了定时循环(您必须检查汇编代码)。

#include <windows.h>
#include <vector>
#include <iostream>

using namespace std;

enum Player
{
    EMPTY = 0,
    BLACK = 1,
    WHITE = 2
};


template <class T, T search>
LONGLONG TimeFunction ()
{
  vector <T>
    vec;

  vec.resize (10000000);

  size_t
    size = vec.size ();

  for (size_t i = 0 ; i < size ; ++i)
  {
      vec [i] = static_cast <T> (rand () % 3);
  }

  LARGE_INTEGER
    start,
    end;

  QueryPerformanceCounter (&start);

  for (size_t i = 0 ; i < size ; ++i)
  {
    if (vec [i] == search)
    {
      break;
    }
  }

  QueryPerformanceCounter (&end);

  return end.QuadPart - start.QuadPart;
}

LONGLONG TimeArrayFunction ()
{
  size_t
    size = 10000000;

  char
    *vec = new char [size];

  for (size_t i = 0 ; i < size ; ++i)
  {
      vec [i] = static_cast <char> (rand () % 3);
  }

  LARGE_INTEGER
    start,
    end;

  QueryPerformanceCounter (&start);

  for (size_t i = 0 ; i < size ; ++i)
  {
    if (vec [i] == 10)
    {
      break;
    }
  }

  QueryPerformanceCounter (&end);

  delete [] vec;

  return end.QuadPart - start.QuadPart;
}

int main ()
{
  cout << "   Char form = " << TimeFunction <char, 10> () << endl;
  cout << "Integer form = " << TimeFunction <int, 10> () << endl;
  cout << " Player form = " << TimeFunction <Player, static_cast <Player> (10)> () << endl;
  cout << "  Array form = " << TimeArrayFunction () << endl;
}

答案 5 :(得分:2)

编译器应将enum转换为整数。它们在编译时被内联,所以一旦你的程序被编译,它应该与你自己使用整数完全一样。

如果您的测试产生不同的结果,测试本身可能会发生一些事情。要么就是这样,要么你的编译器表现得很奇怪。

答案 6 :(得分:2)

这是依赖于实现的,并且枚举和整数很可能具有不同的性能以及相同或不同的汇编代码,尽管它可能是次优编译器的标志。一些获得分歧的方法是:

  • QVector可能专注于你的枚举类型,以做一些令人惊讶的事情。
  • 枚举不会被编译为int,而是“某些整数类型不大于int”。 int的QVector可能与some_integral_type的QVector不同。
  • 即使QVector不是专门的,编译器也可以更好地在内存中对齐int而不是对齐some_integral_type,从而在循环enum向量或some_integral_type时导致更高的缓存未命中率。