C++ C对C++;用于简单阵列创建和i/o的代码优化

C++ C对C++;用于简单阵列创建和i/o的代码优化,c++,optimization,compiler-construction,io,C++,Optimization,Compiler Construction,Io,我一直在试图说服我的一个朋友避免使用动态分配的数组,并开始转向STL向量。我给他发了一些示例代码,向他展示了STL和函子/生成器可以完成的一些事情: #include <iostream> #include <vector> #include <algorithm> #include <iterator> #define EVENTS 10000000 struct random_double { double operator() ()

我一直在试图说服我的一个朋友避免使用动态分配的数组,并开始转向STL向量。我给他发了一些示例代码,向他展示了STL和函子/生成器可以完成的一些事情:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

#define EVENTS 10000000

struct random_double {
  double operator() () { return (double)rand()/RAND_MAX; }
};  

int main(int argc, char **argv){

  std::vector<double> vd (EVENTS);

  generate(vd.begin(), vd.end(), random_double());
  copy(vd.begin(), vd.end(), std::ostream_iterator<double>(std::cout, "\n"));

  return 0;
} 

使用g++的编译器选项是:g++-finline-funroll循环。没什么特别的。有人能告诉我为什么C++/STL版本在这种情况下会慢一些吗?瓶颈在哪里?我能否向我的朋友推销使用STL容器?

在高性能情况下(如游戏),最好避免使用STL容器。是的,它们提供了出色的功能,但也带来了一些开销。这可能是灾难性的

就个人而言,我只使用std的文件处理和临时向量

但是我知道什么呢?;)


编辑:让您的朋友看一看,它试图为GPU上的计算提供类似STL的功能。

几乎可以肯定的是,使用iostream库与使用printf()。如果你想给算法计时,你应该在循环之外进行输出。

使用STL,特别是在使用向量和其他漂亮的实用程序类时,可能总是比使用malloc和内联函数的手动C代码慢。没有真正的解决办法

话虽如此,但性能并不是一切——并非如此。使用STL还有许多其他好处,包括:

  • 更好的可维护性:它更具表现力,因此您可以用更少的代码,以更优雅、干净的方式完成更多的工作
  • 安全性:使用向量比直接处理指针和malloc安全得多
  • 灵活性:例如,通过将向量与函子一起使用,如果需要动态增长此集合,您将有一个更轻松的时间
  • 生产力:通过使代码更干净,STL比许多单独的C例程更有效地促进重用,以完成类似的功能
  • 你真的想争论在更高的抽象级别上工作——这里有一些折衷,通常是在性能方面,但是几乎所有的开发都进入了更高的抽象级别是有原因的;在大多数情况下,收益远比牺牲更有价值。

    使用printf:

      for (std::vector<double>::iterator i = vd.begin(); i != vd.end(); ++i)
         printf("%lf\n", *i);
    

    使用的标志:
    -O2-funroll循环-finline

    可能会出现STL速度较慢的情况,但手动滚动多个插入/删除/查找的贴图/集将很难完成。

    正如尼尔指出的那样,在速度上,PrimTf从IoSover中获胜(Scott Meyers中的一个点也是更有效的C++,点23)。然而,在更复杂的系统中。能够在日志中写出完整的类是值得的。printf方法是在函数中sprintf类信息,并将其作为字符串参数传递给记录器。这样,增益会更小。

    我认为您甚至没有运行相同的代码。
    C代码没有错误检查,并在异常时泄漏内存。
    为了进行比较,你需要让C程序做C++程序所做的事情。
    bool errorNumber = 0;   // Need a way to pass error information back from the function
    int main(int argc, char **argv)
    {
        ......
        {
            vd[i]=random_double();
            //
            // In C++ this logic is implicit with the use of excptions.
            // Any example where you don't do error checking is not valid.
            // In real life any code has to have this logic built in by the developer
            //
            if (errorNumber != 0)
            {    break;
            }
        }
        ........
        free(vd);  The cost of freeing the memory is not zero that needs to be factored in.
        return 0;
    }
    

    相信
    std::cout
    的插入迭代器性能不好,我尝试插入以下functor:

    struct Print {
      void operator()( double d ) { printf("lf\n", d); }
    };
    
    并对stl容器上的每个使用

     generate(vd.begin(), vd.end(), random_double());
      //copy(vd.begin(), vd.end(), std::ostream_iterator<double>(std::cout, "\n"));
      std::for_each(vd.begin(), vd.end(), Print() );
    
    对于STL版本。。。而“原始”版本的结果大致相同

    time.exe raw_vs_stl.exe raw > t.txt
    real    0m 9.22s
    user    0m 7.89s
    sys     0m 
    
    0.67s 结论:矢量性能与原始阵列一样好。它更安全,更容易使用


    (免责声明:使用VC2005)

    了解两种实现之间速度差异的一个技巧是深入研究程序集。组装真的没那么可怕,它向你展示了到底发生了什么。它还可以方便地查看编译器优化了什么。一般来说,汇编指令越多=越长,但请记住,某些指令比其他指令花费的时间要长得多


    (我怀疑,许多其他的IDS)有一个选项来查看与相应C++行交错的程序集。(在VC,这是调试-> Windows -> DISSCOM)。< /P>嗯,C代码在初学者中有明显的内存泄漏。C++比C更受益于-O2。@ Timo:虽然在这种情况下,进程立即结束并将内存返回操作系统。修复了内存泄漏-我向我的朋友指出,这是使用STL的好处之一-更少的内存泄漏:)STL向量也是动态分配的…通常遵循大小加倍算法。STL有很多优点,但这不是其中之一。如果您必须在那里进行输出,请公平竞争并使用printf()。我不同意。在C示例中,唯一可能失败的函数是malloc和printf。如果马洛克记性不好,他可能会提出申请,但在这种极为罕见的情况下,你无论如何也无能为力。。printf在理论上可以保存文件,但在实践中永远不会。无论如何,添加错误检查与性能无关(它将执行得非常快,不会产生任何影响)。至少但不是最后一次,内存将在退出时由操作系统回收,因此free()是不必要的(而且它释放出来是C++的“错误”)。但是,同样地,在5秒钟的执行时间内只有一个free():这无关紧要。我尝试添加错误检查并运行
    time./c>/dev/null
    ,它实际上运行得更快(显然不是因为额外的代码,而是因为中断的不确定性)@Koper:你真的认为没有必要打免费电话吗?即使它在进程退出时被操作系统释放,依赖它也是非常糟糕的编码实践。一个长时间运行的程序可能会使用越来越多的内存,因为不调用free会导致泄漏。此外,并非所有操作系统都会在进程退出时回收内存,特别是那些没有虚拟内存管理器的操作系统。实时嵌入式操作系统通常不支持ha
    struct Print {
      void operator()( double d ) { printf("lf\n", d); }
    };
    
     generate(vd.begin(), vd.end(), random_double());
      //copy(vd.begin(), vd.end(), std::ostream_iterator<double>(std::cout, "\n"));
      std::for_each(vd.begin(), vd.end(), Print() );
    
    time.exe raw_vs_stl.exe stl > t.txt
    real    0m 2.48s
    user    0m 1.68s
    sys     0m 0.28s
    
    time.exe raw_vs_stl.exe raw > t.txt
    real    0m 9.22s
    user    0m 7.89s
    sys     0m