带有文字初始化的c++对const的引用

C++ reference to const with literal initialization

本文关键字:const 引用 c++ 文字 初始化      更新时间:2023-10-16

我对c++进行了更深入的研究,遇到了一个用字面量初始化的const引用。例如

const int &r {100};

它绝对有效,但我想知道编译器用这种定义做什么。是否有一个真正的对象在内存中创建保存值100?或者在编译过程中,每次出现r都简单地用100替换?这是我的猜测,因为初始化值既不能更改,也不能在运行时引用,所以为什么要把它保存在内存中呢?

此处:

const int &r {100};

正在创建临时int,并绑定r。引用const将延长与它绑定的临时对象的生存期。

在以下情况下更有用:

void foo (const std::string& s) {}    
foo("test"); // here temporary std::string is created and later on bound to `s`

理论上("抽象机器"),文字是作为临时对象创建的,然后将引用绑定到它,从而延长了它的使用寿命。

在实践中,编译器被允许改变这个,只要它产生相同的"可观察行为"。所以编译器没有在内存中保存变量。

您可以通过比较g++ -O0 -gg++ -O3 -g的输出并反汇编代码来看到这一点。

短程序:

int main() {
    const int &r {100};
    return r;
}

在没有优化的情况下编译为:

0x00000000004005a8 <+0>: push   %rbp 
0x00000000004005a9 <+1>: mov    %rsp,%rbp 
0x00000000004005ac <+4>: mov    $0x64,%eax 
0x00000000004005b1 <+9>: mov    %eax,-0xc(%rbp) 
0x00000000004005b4 <+12>:    lea    -0xc(%rbp),%rax 
0x00000000004005b8 <+16>:    mov    %rax,-0x8(%rbp) 
0x00000000004005bc <+20>:    mov    -0x8(%rbp),%rax 
0x00000000004005c0 <+24>:    mov    (%rax),%eax 
0x00000000004005c2 <+26>:    pop    %rbp 
0x00000000004005c3 <+27>:    retq    

与完全优化相比,在内存中显然没有引用(即r只是被字面量100替换):

0x00000000004005b0 <+0>:    mov    $0x64,%eax
0x00000000004005b5 <+5>:    retq   

形式上,这将生成一个对象,该对象随后绑定到引用,并且与引用的存在时间一样长。

在某些情况下必须提供对象。考虑这样一种情况:您声明了两个函数,在单独的翻译单元中定义,如下所示:

void foo(int const*);
bool bar(int const*);

现在你做下面的操作:

int main()
{
  const int& r{100};
  foo(&r);
  return bar(&r);
}

编译器不仅要传递一个指向此处具有正确值的对象的指针,还必须传递一个指向同一个对象的指针,因为它不知道另一个翻译单元(可能还没有编写)的实现,例如:

namespace
{
  int const* ptr;
}
void foo(int const* p)
{
  ptr = p;
}
bool bar(int const* p)
{
  return p == ptr && *p = 100;
}

如果在这种情况下,编译器没有创建一个实际的int对象,其值为100,绑定到r,那么结果将是不正确的。