C++等效的C风格数组

Sam*_*Sam 10 c c++ optimization performance

我在这里听到很多人说C++ 在所有方面都比C 快或,但更清洁,更好.

虽然我并不反对C++非常优雅且非常快的事实,但我没有找到关键内存访问或处理器绑定应用程序的替代品.

问题:在性能方面,C风格的数组在C++中是否有等价的?

以下示例是设计的,但我对现实问题的解决方案感兴趣:我开发了图像处理应用程序,并且像素处理的数量巨大.

double t;

// C++ 
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();

t = (double)getTickCount();

for(j=0;j<1000;j++)
{
    count = 0;
    for(i=0;i<size;i++)
         count += v[i];     
}

t = ((double)getTickCount() - t)/getTickFrequency();
std::cout << "(C++) For loop time [s]: " << t/1.0 << std::endl;
std::cout << count << std::endl;

// C-style

#define ARR_SIZE 1000000

int* arr = (int*)malloc( ARR_SIZE * sizeof(int) );

int ci, cj, ccount = 0, csize = ARR_SIZE;

for(ci=0;ci<csize;ci++)
    arr[ci] = 1;

t = (double)getTickCount();

for(cj=0;cj<1000;cj++)
{
    ccount = 0;
    for(ci=0;ci<csize;ci++)
        ccount += arr[ci];      
}

free(arr);

t = ((double)getTickCount() - t)/getTickFrequency();
std::cout << "(C) For loop time [s]: " << t/1.0 << std::endl;
std::cout << ccount << std::endl;
Run Code Online (Sandbox Code Playgroud)

结果如下:

(C++) For loop time [s]: 0.329069

(C) For loop time [s]: 0.229961
Run Code Online (Sandbox Code Playgroud)

注意:getTickCount()来自第三方库.如果您想测试,只需更换您喜欢的时钟测量

更新:

我正在使用VS 2010,发布模式,其他一切都默认

J-1*_*DiZ 12

简单回答:您的基准是有缺陷的.

更长的答案:您需要打开完全优化才能获得C++性能优势.然而,您的基准仍然存在缺陷.

一些观察:

  1. 如果打开完全优化,将删除一大块for循环.这使你的基准毫无意义.
  2. std::vector有动态重新分配的开销,试试std::array.
    具体来说,microsoft的stl 默认检查了迭代器.
  3. 您没有任何障碍来阻止C/C++代码/基准代码之间的交叉重新排序.
  4. (没有真正相关)cout << ccount是语言环境意识,printf不是; std::endl刷新输出,printf("\n")不要.

显示c ++优势的"传统"代码是C qsort()vs C++ std::sort().这是内联代码闪耀的地方.

如果你想要一些"真实的"应用实例.搜索一些光线跟踪器或矩阵乘法的东西.选择一个执行自动矢量化的编译器.

更新 使用LLVM在线演示,我们可以看到整个循环被重新排序.基准代码移动到开始,它跳转到第一个循环中的循环结束点,以便更好地进行分支预测:

(这是c ++代码)

######### jump to the loop end
    jg  .LBB0_11
.LBB0_3:                                # %..split_crit_edge
.Ltmp2:
# print the benchmark result
    movl    $0, 12(%esp)
    movl    $25, 8(%esp)
    movl    $.L.str, 4(%esp)
    movl    std::cout, (%esp)
    calll   std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
.Ltmp3:
# BB#4:                                 # %_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc.exit
.Ltmp4:
    movl    std::cout, (%esp)
    calll   std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<double>(double)
.Ltmp5:
# BB#5:                                 # %_ZNSolsEd.exit
    movl    %eax, %ecx
    movl    %ecx, 28(%esp)          # 4-byte Spill
    movl    (%ecx), %eax
    movl    -24(%eax), %eax
    movl    240(%eax,%ecx), %ebp
    testl   %ebp, %ebp
    jne .LBB0_7
# BB#6:
.Ltmp52:
    calll   std::__throw_bad_cast()
.Ltmp53:
.LBB0_7:                                # %.noexc41
    cmpb    $0, 28(%ebp)
    je  .LBB0_15
# BB#8:
    movb    39(%ebp), %al
    jmp .LBB0_21
    .align  16, 0x90
.LBB0_9:                                #   Parent Loop BB0_11 Depth=1
                                        # =>  This Inner Loop Header: Depth=2
    addl    (%edi,%edx,4), %ebx
    addl    $1, %edx
    adcl    $0, %esi
    cmpl    %ecx, %edx
    jne .LBB0_9
# BB#10:                                #   in Loop: Header=BB0_11 Depth=1
    incl    %eax
    cmpl    $1000, %eax             # imm = 0x3E8
######### jump back to the print benchmark code
    je  .LBB0_3
Run Code Online (Sandbox Code Playgroud)

我的测试代码:

std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();

for(j=0;j<1000;j++)
{
    count = 0;
    for(i=0;i<size;i++)
         count += v[i];     
}

std::cout << "(C++) For loop time [s]: " << t/1.0 << std::endl;
std::cout << count << std::endl;
Run Code Online (Sandbox Code Playgroud)

  • (2)不是真的.在时间检查之前,数组会提前调整大小,因此不会执行重新分配.至于(1)我(部分地)展开循环(以减少与循环相关的东西)并使计数易失性以排除不希望的优化 (2认同)
  • @ J-16SDiZ 2010年_SECURE_SCL的默认值为0 http://msdn.microsoft.com/en-us/library/aa985896.aspx (2认同)

han*_*aad 11

问题:在性能方面,C风格的数组在C++中是否有等价的?

答:编写C++代码!了解您的语言,了解您的标准库并使用它.标准算法是正确的,可读的和快速的(他们知道如何在当前编译器上快速实现它).

void testC()
{
    // unchanged
}

void testCpp()
{
    // unchanged initialization

    for(j=0;j<1000;j++)
    {
        // how a C++ programmer accumulates:
        count = std::accumulate(begin(v), end(v), 0);    
    }

    // unchanged output
}

int main()
{
    testC();
    testCpp();
}
Run Code Online (Sandbox Code Playgroud)

输出:

(C) For loop time [ms]: 434.373
1000000
(C++) For loop time [ms]: 419.79
1000000
Run Code Online (Sandbox Code Playgroud)

g++ -O3 -std=c++0x在Ubuntu上使用4.6.3版编译.

对于您的代码,我的输出与您的类似.user1202136对差异给出了很好的答案......


use*_*136 8

这似乎是一个编译器问题.对于C阵列,编译器检测模式,使用自动向量化并发出SSE指令.对于载体,它似乎缺乏必要的智能.

如果我强制编译器不使用SSE,结果非常相似(测试g++ -mno-mmx -mno-sse -msoft-float -O3):

(C++) For loop time [us]: 604610
1000000
(C) For loop time [us]: 601493
1000000
Run Code Online (Sandbox Code Playgroud)

以下是生成此输出的代码.它基本上是你问题中的代码,但没有任何浮点.

#include <iostream>
#include <vector>
#include <sys/time.h>

using namespace std;

long getTickCount()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000000 + tv.tv_usec;
}

int main() {
long t;

// C++ 
std::vector<int> v;
v.resize(1000000,1);
int i, j, count = 0, size = v.size();

t = getTickCount();

for(j=0;j<1000;j++)
{
    count = 0;
    for(i=0;i<size;i++)
         count += v[i];     
}

t = getTickCount() - t;
std::cout << "(C++) For loop time [us]: " << t << std::endl;
std::cout << count << std::endl;

// C-style

#define ARR_SIZE 1000000

int* arr = new int[ARR_SIZE];

int ci, cj, ccount = 0, csize = ARR_SIZE;

for(ci=0;ci<csize;ci++)
    arr[ci] = 1;

t = getTickCount();

for(cj=0;cj<1000;cj++)
{
    ccount = 0;
    for(ci=0;ci<csize;ci++)
        ccount += arr[ci];      
}

delete arr;

t = getTickCount() - t;
std::cout << "(C) For loop time [us]: " << t << std::endl;
std::cout << ccount << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

  • @LutherBlissett对不起,SSE或MMX*就是问题所在.我查看了汇编器输出.优化已经通过`-O3`打开了.我使用`gettimeofday`,因为我听说`getrusage`的分辨率很差.为了减少基准测试错误,我确保系统大部分处于空闲状态,并且我运行了几次基准测试,结果相似. (6认同)