当有问题的getter返回引用时访问成员变量有多昂贵?
例如,如果你有一个需要经常使用这种访问器的类,那么在需要使用它的类中存储所述引用并简单地初始化一次会有多高效?
答案 0 :(得分:5)
获取函数通常不应返回引用。这样做的原因是它使该成员对公众开放 - 如果你想这样做只是让它成为一个公共成员。
class foo {
int bar;
public:
int& get_bar() { return bar; } // this is silly! Just make bar public!
}
无论如何,如果它像get_bar
一样简单,它将被内联到类似foo.bar
的内容。正如Oli指出的那样,您也可以将它作为const引用,但对于像int
这样的小类型,您应该继续按值返回。
对于更昂贵的类型,参考开始是有益的。你可以假设:
例如:
foo x;
x.get_value().func(); // calls copy constructor at least once and destructor
x.get_reference().func(); // may require dereference when using
答案 1 :(得分:3)
关于复杂性,返回或传递引用就像传递指针一样。它的开销相当于传递一个指针大小的整数,加上一些指令。简而言之,几乎在所有情况下都尽可能快。小于或等于指针大小的内置类型(例如int,float)是明显的例外。
最坏的情况是,传递/返回引用可以添加一些指令或禁用某些优化。这些损失很少超过按值返回/传递对象的成本(例如,调用复制构造函数+析构函数要高得多,即使是非常基本的对象)。通过引用传递/返回是一个很好的默认值,除非每条指令都很重要,并且你已经测量了这种差异。
因此,使用引用的开销非常低。
如果不了解类型及其构造函数/析构函数的复杂性,就无法真正量化 的速度,但如果它不是内置类型,那么持有本地并返回在大多数情况下,它通过引用将是最快的 - 这一切都取决于对象及其副本的复杂性,但只有令人难以置信的微不足道的对象才能接近参考的速度。
答案 2 :(得分:1)
如果函数定义可用且相对简单,那么这样的函数将被内联,并且与直接访问成员相比,没有任何开销。否则,操作序列就像获取地址类/结构对象,应用偏移量来获取成员的地址,以及将此地址返回给调用者一样简单。现在,对于这些情况,仅当对象是不可复制的或者其大小大于指针的大小时才通过引用返回是有意义的。不可复制对象的原因是显而易见的,否则你会看到复制开销 - 结构的大小与指针的大小。所以经验法则是这样 - 通过引用(或指针)返回大对象,通过复制它们返回小对象(整数,双精度等)。在那些您无需控制成员访问权限的情况下 - 只需使用对成员具有公共访问权限的结构,并且不要使用大量的getter和setter来破坏您的代码。
答案 3 :(得分:1)
坦率地说,如果你开始想知道这个开销:你有没有想过调用约定,使用stdcall而不是cdecl?
你从中获得的速度与你在讨论时所说的相似。