Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么访问类的私有变量和访问结构的变量一样高效?_C++_Algorithm_Struct - Fatal编程技术网

C++ 为什么访问类的私有变量和访问结构的变量一样高效?

C++ 为什么访问类的私有变量和访问结构的变量一样高效?,c++,algorithm,struct,C++,Algorithm,Struct,我实现了一些主要数据结构是树的算法。我用一个类来表示一个节点,用一个类来表示一棵树。由于节点得到了大量更新,我调用了许多setter和getter 因为我多次听说函数调用很昂贵,我在想,如果我用结构表示节点和树,可能会使我的算法在实践中更有效 在这样做之前,我决定做一个小实验,看看是否真的是这样 我创建了一个类,它有一个私有变量、一个setter和一个getter。我还创建了一个结构,它也有一个变量,没有setters/getter,因为我们可以通过调用struct.varName来更新变量。结

我实现了一些主要数据结构是树的算法。我用一个类来表示一个节点,用一个类来表示一棵树。由于节点得到了大量更新,我调用了许多setter和getter

因为我多次听说函数调用很昂贵,我在想,如果我用结构表示节点和树,可能会使我的算法在实践中更有效

在这样做之前,我决定做一个小实验,看看是否真的是这样

我创建了一个类,它有一个私有变量、一个setter和一个getter。我还创建了一个结构,它也有一个变量,没有setters/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;
}
#包括
#包括
#定义十亿亿
使用名称空间std;
福班{
私人:
INTA;
公众:
无效集(int newA){
a=新a;
}
int get(){
返回a;
}
};
结构条{
INTA;
};
timespec startT,endT;
void startTimer(){
时钟获取时间(时钟处理时间ID和启动时间);
}
双端定时器(){
时钟获取时间(时钟处理时间ID和结束时间);
返回endT.tv_sec*000000+endT.tv_nsec-(startT.tv_sec*000000+startT.tv_nsec);
}
int main(){
整数运行=10000000;
int startRun=10000;
int步长=10000;
int迭代次数=10;
int res=0;
福福;
流式流量计;
fout.open(“stats.txt”,ios_base::out);
福特
我听过很多次函数调用是昂贵的

这是1970年的事吗

编译器是聪明的。非常聪明。它们能为你的源代码生成最好的程序,除非你做了一些非常奇怪的事情,否则这些类型的设计更改不太可能产生太大的(如果有的话)性能差异

这里最值得注意的是,在大多数情况下,一个简单的getter/setter甚至可以完全内联(除非你做了一些奇怪的事情),这使得你的两个程序在编译后实际上是相同的!你可以在图表上看到这个结果

同时,用
struct
替换
class
的具体变化对性能没有任何影响-这两个关键字都定义了一个类

我不明白为什么我会有这种行为。我以为函数调用更昂贵


看,这就是为什么我们不过早地进行优化。编写清晰易读的代码而不需要技巧,让编译器来处理其余的部分。这就是它的工作,而且它通常非常擅长于此。

这里的答案几乎肯定是编译器优化。首先,在类定义中定义getter和setter会使它们变得更简单。甚至但是,如果您没有这样做,我希望任何现代编译器都能优化掉函数调用,如果它们在同一个文件中,并且编译器知道结果对象是整个程序。

您能发布用于编译代码的命令吗?编译器很聪明。很有可能您的getter和setter会优化掉comp另外,公共/私有访问器对运行时性能没有影响,它们只在编译时进行检查。访问私有类成员和公共结构成员不会导致性能损失。旁白:在实际测量和分析更改方面做得很好。这是任何合理优化过程的第二条规则。不毫无疑问,您错过的第一条规则是对原始代码进行分析,以实际查看是否存在问题!无论哪种方式,这都是一个很好的教训。请更换实验顺序,并确保获得相同的结果,以消除“外部因素”例如缓存状态等@jsguy:既然你已经确定你的编译器默认不会内联单独编译的代码,你可以尝试全局优化(你可以认为这是在链接时执行的)。Re“编译器很聪明,非常聪明。”,这是一个流传很广的神话。的确,编译器有一些普通开发人员永远不会想到的内置智能,例如用疯狂的位级技巧折叠算术表达式。但在主要编译器中,它们仍然非常非常愚蠢。看看gcc生成的代码。即使是新手汇编程序员也可以做得更好呃,第一次尝试。@cheers-sandhth.-Alf编译器很聪明;它们不是魔法。部分问题是C/C++标准要求汇编程序员不必担心的东西(或者可能想象不需要,然后被咬了一口)问题的另一部分是,编译器通常很难确保优化是安全的(而草率的编程会让这更糟)。最主要的问题是,你希望编译器运行得快,并使用合理的内存。@Cheersandhth.-Alf我已经做过几次了,每次都对gcc是多么聪明感到惊讶。我有一些编写汇编的经验,可能可以被称为“新手”,但我不能打败gcc,所以你错了。这就是现代,整个程序优化应该使用LTO来实现,而不是将整个实现强制放在一个cpp文件中。我运行了一些实验来测试这一点,似乎如果我在一个文件中声明类并在一个单独的.cpp文件中实现setter/getter,我会得到非常差的性能。。。