[英]Where is the const& args stored?
这是 function 定义
const int& test_const_ref(const int& a) {
return a;
}
并从main
调用它
int main() {
auto& x = test_const_ref(1);
printf("%d, %p\n", x, &x);
}
output 如下
./debug/main
>>> 1, 0x7ffee237285c
这是test_const_ref
的反汇编代码
test_const_ref(int const&):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
popq %rbp
retq
问题是:变量x
别名或我传递给 function test_const_ref
的数字1
存储在哪里?
该代码表现出未定义的行为- function test_const_ref
返回一个对临时的引用,该引用一直存在到完整表达式( ;
)的末尾,之后对其的任何取消引用都会访问一个悬空引用。
出现工作是UB的常见表现。 程序仍然是错误的。 例如,通过优化Clang 12 -O2打印: 0
。
注意 - function test_const_ref
本身没有错误(除了设计错误)。 UB 在main
中,在调用printf
期间,悬空int&
的取消引用发生。
临时int
准确存储的位置是实现细节 - 但在许多情况下(在调试版本中,当 function 未内联时),它将存储在堆栈中:
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov dword ptr [rbp - 12], 1 # Here the 1 is stored in the stack frame
lea rdi, [rbp - 12]
call test_const_ref(int const&)
mov qword ptr [rbp - 8], rax
mov rax, qword ptr [rbp - 8]
mov esi, dword ptr [rax]
mov rdx, qword ptr [rbp - 8]
movabs rdi, offset .L.str
mov al, 0
call printf
因此,任何后续使用返回的引用都将访问[rbp - 12]
处的 memory ,这可能已经被重新用于其他目的。
另请注意,编译器实际上并未从 C++ 代码生成程序集; 它仅使用 C++ 代码来理解意图,并生成另一个程序来生成预期的 output。 这被称为假设规则。 在存在未定义行为的情况下,编译器不受此限制,可能会生成任何output,从而使程序变得毫无意义。
已经给出了很好的答案,但是wrapperm 在这里很好地解释了这个主题。 在我知道的大多数实现中,它将存储在堆栈中。
该语言没有定义 arguments 到函数的存储位置。 针对不同平台的不同 ABI 对此进行了定义。
通常,在进行任何优化之前,function 参数存储在堆栈中。 参考在这方面没有什么不同。 实际存储的是指向 object 的指针。 这样想:
const int* test_const_ref(const int* a) {
return a;
}
如果你要声明一个变量int foo;
并调用test_const_ref(foo)
,您知道结果将引用foo
。 由于您使用临时调用它,因此所有赌注都已关闭:正如@fabian 在评论中指出的那样,该语言仅保证该值存在直到赋值语句结束。 然后
在实践中,在您的情况下:为临时 integer 1
分配堆栈空间的编译器将x
引用该位置,并且在定义x
之前不会将其用于其他用途。 但是,如果您的编译器优化了该堆栈分配 - 例如通过寄存器传递1
- 那么x
没有可引用的内容并且可能包含垃圾。 它甚至可能是未定义的行为(对此不太确定)。 如果你幸运的话,你会得到一个关于它的编译器警告(GodBolt.org)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.