[英]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.