内联传递引用函数是否仍然创建引用变量?

Do inlined pass-by-reference functions still create reference variables?

我正在编写一个具有一些状态变量的循环。

int MyFunc(){
    int state_variable_1 = 0;
    int state_variable_2 = 12;

    while(state_variable_1 != state_variable_2){
        BodyOfWhileLoop(state_variable_1, state_variable_2);
    }
}

如您所见,我将 while 循环的主体写在一个单独的函数中,BodyOfWhileLoop。这是为了保持代码干净并有助于调试。

BodyOfWhileLoop 将需要修改 state_variable_1state_variable_2。我可以通过引用传递这些,例如,

void BodyOfWhileLoop(int& state_variable_1, int& state_variable_2);

这在功能上正是我想要的,但是,在函数体中每次使用状态变量都需要取消引用(我相信)。我可以这样做:

void BodyOfWhileLoop(int& state_variable_1_ref, int& state_variable_2_ref){
    int state_variable_1_copy = state_variable_1_ref; 
    int state_variable_2_copy = state_variable_2_ref; 

    // Do stuff with state variables
    
    state_variable_1_ref = state_variable_1_copy; 
    state_variable_2_ref = state_variable_2_copy; 
}

我认为有两件事是正确的:

  1. 复制状态变量会消耗内存,因为您为副本分配了 space。
  2. 不复制状态变量会花费时间,因为每次访问状态变量时 BodyOfWhileLoop 的主体中都会有一个额外的取消引用。

所以我有两个问题:

  1. 如果编译器内联 BodyOfWhileLoop,它是否仍会创建 state_variable_1_refstate_variable_2_ref(需要取消引用才能访问 int)?访问 state_variable_1 的费用是否与在 MyFunc 内访问的费用相同?
  2. 有没有我没见过的替代解决方案?

不,他们没有。示范:https://godbolt.org/z/qc1ne7ezM.

引用通常在幕后实现为指针(尽管它们不一定是)。内联函数后,编译器将消除间接寻址。在 LLVM 中,此优化作为 SROA.

的一部分执行

任何只有一个调用点的函数都应该被优化器内联,但请注意,如果一个函数有外部链接,编译器可能不会内联它:它可以在其他翻译单元中使用,所以编译器不知道它是唯一的用过一次。为避免这种情况,将其标记为staticinline,或使用link-time优化。

C++ 标准不要求 C++ 编译器以任何特定方式生成编译代码。 C++ 标准指定了 well-formed C++ 代码的结果,而编译器如何去做完全取决于编译器。没有两个 C++ 编译器是相同的,不同的 C++ 编译器可能会采用不同的方法并从中等复杂度的 C++ 程序中生成不同的编译代码。

此外,越来越多的 C++ 编译器已经发展到实现新的 link-time 优化技术,这些技术将可能的优化范围扩展到传统上可能的范围之外,到目前为止。

通常,允许 C++ 编译器实现任何没有明显效果的优化。如果您的 C++ 编译器可以证明您所考虑的优化没有明显的效果,那么您的 C++ 编译器可以(但没有义务)实现它。

编译器是否最终进行此优化或任何其他优化完全取决于编译器,最终结果也可能因编译选项而异。所以,对于这类问题没有明确的答案,除了编译代码然后检查生成的编译机器代码以查看您的编译器目录。