假设您有一个包含私有(private)成员的类,这些成员在程序中经常被访问(例如在必须快速的循环中)。想象一下,我定义了这样的东西:
class Foo
{
public:
Foo(unsigned set)
: vari(set)
{}
const unsigned& read_vari() const { return vari; }
private:
unsigned vari;
};
我想这样做的原因是,一旦创建了类,“vari”就不应再更改。因此,为了尽量减少错误的发生,“这在当时看来是个好主意”。
但是,如果我现在需要调用此函数数百万次,我想知道是否存在开销和速度减慢而不是简单地使用:
struct Foo
{
unsigned vari;
};
那么,我使用类的第一个冲动是否正确,以避免任何人在构造函数设置变量后错误地更改变量的值? 此外,这是否会以函数调用开销的形式引入“惩罚”。 (假设我在编译器中使用优化标志,例如 GCC 中的 -O2)?
最佳答案
他们应该是一样的。还记得您尝试在 vector 上使用 operator[]
而 gdb
只是回复 optimized out
的沮丧时刻吗?这就是这里将要发生的事情。编译器不会在此处创建函数调用,而是直接访问变量。
让我们看看下面的代码
struct foo{
int x;
int& get_x(){
return x;
}
};
int direct(foo& f){
return f.x;
}
int fnc(foo& f){
return f.get_x();
}
它是用 g++ test.cpp -o test.s -S -O2
编译的。 -S
标志告诉编译器“在适当的编译阶段后停止;不要汇编(引用自 g++ 联机帮助页)”。这是编译器给我们的:
_Z6directR3foo:
.LFB1026:
.cfi_startproc
movl (%rdi), %eax
ret
和
_Z3fncR3foo:
.LFB1027:
.cfi_startproc
movl (%rdi), %eax
ret
如您所见,在第二种情况下没有进行任何函数调用,它们是相同的。这意味着使用访问器方法没有性能开销。
奖励:如果关闭优化会发生什么?同样的代码,结果如下:
_Z6directR3foo:
.LFB1022:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movl (%rax), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
和
_Z3fncR3foo:
.LFB1023:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movq %rdi, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rdi
call _ZN3foo5get_xEv #<<<call to foo.get_x()
movl (%rax), %eax
leave
.cfi_def_cfa 7, 8
ret
如您所见,在没有优化的情况下,结构比访问器快,但是谁在没有优化的情况下发布代码呢?
关于c++ - 返回私有(private)类成员是否比使用结构并直接访问该变量慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23125713/