jsg*_*guy 9 c++ algorithm struct
我实现了一些主数据结构是树的算法.我使用一个类来表示一个节点和一个表示树的类.因为节点得到了很多更新,所以我称之为许多setter和getter.
因为我多次听说函数调用很昂贵,所以我想也许如果我使用结构表示节点和树,它会使我的算法在实践中更有效率.
在这样做之前,我决定进行一个小实验,看看是否真的如此.
我创建了一个有一个私有变量,一个setter和一个getter的类.此外,我创建了一个具有一个变量的结构,没有setter/getter,因为我们可以通过调用来更新变量struct.varName.结果如下:
运行次数是我们调用setter/getter的次数.这是实验的代码:
#include <iostream>
#include <fstream>
#define BILLION  1000000000LL
using namespace std;
class foo{
private:
    int a;
public:
    void set(int newA){
        a = newA;
    }
    int get(){
        return a;
    }
};
struct bar{
    int a;
};
timespec startT, endT;
void startTimer(){
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &startT);
}
double endTimer(){
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &endT);
    return endT.tv_sec * BILLION + endT.tv_nsec - (startT.tv_sec * BILLION + startT.tv_nsec);
}
int main() {
    int runs = 10000000;
    int startRun = 10000;
    int step = 10000;
    int iterations = 10;
    int res = 0;
    foo f;
    ofstream fout;
    fout.open("stats.txt", ios_base::out);
    fout<<"alg\truns\ttime"<<endl;
    cout<<"First experiment progress: "<<endl;
    int cnt = 0;
    for(int run = startRun; run <= runs; run += step){
        double curTime = 0.0;
        for(int iter = 0; iter < iterations; iter++) {
            startTimer();
            for (int i = 1; i <= run; i++) {
                f.set(i);
                res += f.get();
            }
            curTime += endTimer()/iterations;
            cnt++;
            if(cnt%10 == 0)
                cout<<cnt/(((double)runs-startRun+1)/step*iterations)*100<<"%\r";
        }
        fout<<"class\t"<<run<<"\t"<<curTime/BILLION<<endl;
    }
    int res2 = 0;
    bar b;
    cout<<"Second experiment progress: "<<endl;
    cnt = 0;
    for(int run = startRun; run <= runs; run += step){
        double curTime = 0.0;
        for(int iter = 0; iter < iterations; iter++) {
            startTimer();
            for (int i = 1; i <= run; i++) {
                b.a = i;
                res2 += b.a;
            }
            curTime += endTimer()/iterations;
            cnt++;
            if(cnt%10 == 0)
                cout<<cnt/(((double)runs-startRun+1)/step*iterations)*100<<"%\r";
        }
        fout<<"struct\t"<<run<<"\t"<<curTime/BILLION<<endl;
    }
    fout.close();
    cout<<res<<endl;
    cout<<res2<<endl;
    return 0;
}
我不明白为什么我会这样做.我觉得功能调用更贵?
编辑:我没有-O3重新运行相同的实验
编辑:好的,这是非常令人惊讶的,通过在一个单独的文件中声明该类,在-O3中foo.h实现getter/setter foo.cpp并运行它,似乎该类变得更加低效.
Lig*_*ica 10
我多次听说函数调用很贵.
这是1970年的任何机会吗?
编译器很聪明.很聪明.他们生成了他们可以提供源代码的最佳程序,除非你做了一些非常奇怪的事情,否则这些类型的设计更改不太可能产生太多(如果有的话)性能差异.
最值得注意的是,在大多数情况下,一个简单的getter/setter甚至可以完全内联(除非你做了一些奇怪的事情),让你的两个程序在编译后有效地相同!您可以在图表上看到此结果.
同时,更换的具体变化class与struct对性能没有影响任何-这两个关键字定义一个类.
我不明白为什么我会这样做.我觉得功能调用更贵?
看,这就是我们不过早优化的原因.编写清晰,易于阅读的代码,无需技巧,让编译器完成剩下的工作.这是它的工作,而且它通常非常擅长.