对会员功能的重复呼叫会受到伤害吗?

Rah*_*mri 1 c++ performance inline function member-functions

我已经用Java和C编程了,现在我想用C++弄脏自己.

鉴于此代码:

class Booth {

private :
          int tickets_sold;
public :
          int get_tickets_sold();
          void set_tickets_sold();
};
Run Code Online (Sandbox Code Playgroud)

在Java中,无论我需要什么值tickets_sold,我都会反复调用getter.

例如:

if (obj.get_tickets_sold() > 50 && obj.get_tickets_sold() < 75){
     //do something
}
Run Code Online (Sandbox Code Playgroud)

在CI中,只需获取结构中特定变量的值:

if( obj_t->tickets_sold > 50 && obj_t->tickets_sold < 75){
    //do something
}
Run Code Online (Sandbox Code Playgroud)

因此,当在C中使用结构时,我节省了两次调用,否则我将在Java中使用,两个getter就是,我甚至不确定这些是实际调用还是Java以某种方式内联这些调用.

我的观点是,如果我使用与C++中的Java相同的技术,那两个对getter成员函数的调用是否会花费我,或者编译器是否知道内联代码?(从而减少了函数调用的开销?)

或者,我最好使用:

int num_tickets = 0;

if ( (num_tickets = obj.get_ticket_sold()) > 50 && num_tickets < 75){
    //do something
}
Run Code Online (Sandbox Code Playgroud)

我想编写严格的代码并避免不必要的函数调用,我会在Java中关心这个,因为,我们都知道为什么.但是,我希望我的代码可读,并使用privatepublic关键字来正确反映要做的事情.

Jam*_*lis 8

除非你的程序太慢,否则它并不重要.在99.9999%的代码中,函数调用的开销是微不足道的.写下最清晰,最容易维护,最容易理解的代码,只有在知道性能热点之后才开始调整性能,如果你有的话.

也就是说,现代C++编译器(以及一些链接器)可以并且将内联函数,尤其是像这样的简单函数.


Ton*_*roy 5

如果你只是学习这门语言,你真的不应该担心这个.除非另有证明,否则请考虑它.也就是说,这里有很多误导或不完整的答案,所以为了记录,我将充实一些更微妙的含义.考虑你的班级:

class Booth
{
  public:
    int get_tickets_sold();
    void set_tickets_sold();
  private:
    int tickets_sold;
};
Run Code Online (Sandbox Code Playgroud)

尚未指定get和set函数的实现(称为定义).如果您在类声明中指定了函数体,那么编译器会认为您已隐式请求它们被内联(但如果它们过大则可能会忽略它).如果您稍后使用inline关键字指定它们,则具有完全安全的效果.综上所述...

class Booth
{
  public:
    int get_tickets_sold() { return tickets_sold; }
    ...
Run Code Online (Sandbox Code Playgroud)

...和...

class Booth
{
  public:
    int get_tickets_sold();
    ...
};

inline int Booth::get_tickets_sold() { return tickets_sold; }
Run Code Online (Sandbox Code Playgroud)

......是等价的(至少在标准鼓励我们期望的方面,但个别编译器启发式可能会有所不同 - 内联是编译器可以自由忽略的请求).

如果稍后在没有inline关键字的情况下指定函数体,则编译器没有义务内联它们,但仍可能选择这样做.如果它们出现在相同的翻译单元中(即在您正在编译的.cc/.cpp/.c ++/etc."实现"文件或直接或间接包含的某些标题中),则更有可能这样做. 如果实现仅在链接时可用,那么函数可能根本不会内联,但这取决于特定编译器和链接器交互和协作的方式.这不是简单地实现优化和期待神奇的事.为了证明这一点,请考虑以下代码:

// inline.h:
void f();

// inline.cc:
#include <cstdio>
void f() { printf("f()\n"); }

// inline_app.cc:
#include "inline.h"
int main() { f(); }
Run Code Online (Sandbox Code Playgroud)

建立这个:

g++ -O4 -c inline.cc
g++ -O4 -o inline_app inline_app.cc inline.o
Run Code Online (Sandbox Code Playgroud)

调查内联:

$ gdb inline_app 
...
(gdb) break main
Breakpoint 1 at 0x80483f3
(gdb) break f
Breakpoint 2 at 0x8048416
(gdb) run
Starting program: /home/delroton/dev/inline_app 

Breakpoint 1, 0x080483f3 in main ()
(gdb) next
Single stepping until exit from function main, 
which has no line number information.

Breakpoint 2, 0x08048416 in f ()
(gdb) step
Single stepping until exit from function _Z1fv, 
which has no line number information.
f()
0x080483fb in main ()
(gdb) 
Run Code Online (Sandbox Code Playgroud)

注意执行从main()中的0x080483f3到f()中的0x08048416然后返回到main()中的0x080483fb ...显然没有内联.这说明内联不能仅仅因为函数的实现是微不足道的.

请注意,此示例使用目标文件的静态链接.显然,如果您使用库文件,您实际上可能希望避免专门内联函数,以便您可以更新库而无需重新编译客户端代码.对于共享库来说,它甚至更有用,无论如何,链接在加载时隐式完成.

通常,提供简单函数的类使用两种形式的expect-inlined函数定义(即内部类或带有inline关键字),如果可以预期在任何性能关键循环中调用这些函数,但反对的考虑是通过内联函数强制客户端代码重新编译(相对较慢,可能没有自动触发)并重新链接(快速,对于共享库在下次执行时发生),而不是仅重新链接,以便获取对函数实现的更改.

这些考虑因素很烦人,但是对这些权衡的有意管理是允许企业使用C和C++扩展到数万亿行和数千个单独项目的过程,这些项目在几十年内共享各种库.

另一个小细节:作为一个球场图,一个外线获取/设置函数通常比同等内联代码慢一个数量级(10x).这显然会随CPU,编译器,优化级别,变量类型,缓存命中/未命中等而变化.