返回私有类成员的速度是否比使用结构并直接访问该变量慢
Is returning a private class member slower than using a struct and accessing that variable directly?
假设你有一个类,它有私有成员,这些成员在程序中被大量访问(例如在一个必须快速的循环中(。想象一下,我定义了这样的东西:
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(?
他们应该是一样的。还记得您尝试在矢量上使用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++类都依赖于此 - 例如,C++11 的list::size() const
可以预期会简单地返回数据成员。 (这与vector()
形成鲜明对比,其中的实现我看过将size()
计算为对应于begin()
和end()
的指针数据成员之间的差异,如果优化器无法确定size()
在循环迭代中是恒定的,则确保典型的迭代器使用尽可能快,代价是索引迭代可能变慢(。
对于像 unsigned
这样的类型,通常没有特别的理由通过引用const
返回,无论如何都应该适合 CPU 寄存器,但由于它是内联的,编译器不必从字面上理解这一点(对于外联版本,它可能会通过返回必须取消引用的指针来实现(。 (非典型的原因是允许获取变量的地址,这就是为什么说vector::operator[](size_t) const
需要返回一个const T&
而不是一个T
,即使T
足够小以适合寄存器。
只有一种方法可以确定在您的特定程序中,哪一个更快,在您的特定程序中,使用您的特定工具在您的特定平台上使用您的特定优化标志 - 通过测量两个变体。
话虽如此,二进制文件很有可能是相同的,指令对指令。
正如其他人所说,如今的优化器被用来浓缩抽象(特别是在C++中,它或多或少是为了利用这一点而构建的(,它们非常非常好。
但是您可能不需要为此使用吸气剂。
struct Foo {
Foo(unsigned set) : vari(set) {}
unsigned const vari;
};
const
并不禁止初始化。
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 访问存储在向量C++中的结构的多态成员
- 访问类lintalizer列表中的结构元素
- 仅使用结构名称访问结构成员
- 如何从其他结构访问受保护的结构变量
- 如何从类中定义的结构访问私有成员?c++
- 枚举范围无法通过 C++ 中的类中的结构访问
- 通过更高级别的结构访问子变量
- 从匿名结构访问枚举条目
- 如何定义别名以通过结构访问枚举类成员
- C 用于向量中的结构访问索引或使用参考值
- 奇怪的结构访问错误
- 将数组作为结构访问与未定义的行为
- 使用c++以及x86和x64体系结构访问处理器中断
- 使用 ostream 从另一个类的结构访问数据
- 从结构访问数组会使程序崩溃
- 联合中的C++结构访问联合成员
- SWIG如何使用Lua表从Lua中的c结构访问字节数组
- c++结构访问冲突