Temporaries không có bộ nhớ. Họ được cấp phát trên stack của người gọi (lưu ý: có thể là chủ đề của cuộc gọi hội nghị, nhưng tôi nghĩ họ ngăn xếp tất cả sử dụng của người gọi):
caller()
{
callee1(Tmp());
callee2(Tmp());
}
trình biên dịch sẽ phân bổ không gian cho kết quả Tmp()
trên stack của caller
. Bạn có thể lấy địa chỉ của vị trí bộ nhớ này - nó sẽ là một số địa chỉ trên ngăn xếp của caller
.Trình biên dịch nào không đảm bảo rằng nó sẽ bảo tồn các giá trị tại địa chỉ ngăn xếp này sau khi trả về callee
. Ví dụ, trình biên dịch có thể đặt có khác tạm thời, vv
EDIT: Tôi tin rằng, nó không được phép để loại bỏ mã như thế này:
T bar();
T * ptr = &bar();
vì nó sẽ rất có thể dẫn đến vấn đề này.
EDIT: đây là một little test:
#include <iostream>
typedef long long int T64;
T64 ** foo(T64 * fA)
{
std::cout << "Address of tmp inside callee : " << &fA << std::endl;
return (&fA);
}
int main(void)
{
T64 lA = -1;
T64 lB = -2;
T64 lC = -3;
T64 lD = -4;
T64 ** ptr_tmp = foo(&lA);
std::cout << "**ptr_tmp = *(*ptr_tmp) = lA\t\t\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lA << std::endl << std::endl;
foo(&lB);
std::cout << "**ptr_tmp = *(*ptr_tmp) = lB (compiler override)\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lB << std::endl
<< std::endl;
*ptr_tmp = &lC;
std::cout << "Manual override" << std::endl << "**ptr_tmp = *(*ptr_tmp) = lC (manual override)\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp
<< " = " << lC << std::endl << std::endl;
*ptr_tmp = &lD;
std::cout << "Another attempt to manually override" << std::endl;
std::cout << "**ptr_tmp = *(*ptr_tmp) = lD (manual override)\t\t**" << ptr_tmp << " = *(" << *ptr_tmp << ") = " << **ptr_tmp << " = " << lD << std::endl
<< std::endl;
return (0);
}
Chương trình đầu ra GCC:
Address of tmp inside callee : 0xbfe172f0
**ptr_tmp = *(*ptr_tmp) = lA **0xbfe172f0 = *(0xbfe17328) = -1 = -1
Address of tmp inside callee : 0xbfe172f0
**ptr_tmp = *(*ptr_tmp) = lB (compiler override) **0xbfe172f0 = *(0xbfe17320) = -2 = -2
Manual override
**ptr_tmp = *(*ptr_tmp) = lC (manual override) **0xbfe172f0 = *(0xbfe17318) = -3 = -3
Another attempt to manually override
**ptr_tmp = *(*ptr_tmp) = lD (manual override) **0xbfe172f0 = *(0x804a3a0) = -5221865215862754004 = -4
đầu ra Chương trình VC++:
Address of tmp inside callee : 00000000001EFC10
**ptr_tmp = *(*ptr_tmp) = lA **00000000001EFC10 = *(000000013F42CB10) = -1 = -1
Address of tmp inside callee : 00000000001EFC10
**ptr_tmp = *(*ptr_tmp) = lB (compiler override) **00000000001EFC10 = *(000000013F42CB10) = -2 = -2
Manual override
**ptr_tmp = *(*ptr_tmp) = lC (manual override) **00000000001EFC10 = *(000000013F42CB10) = -3 = -3
Another attempt to manually override
**ptr_tmp = *(*ptr_tmp) = lD (manual override) **00000000001EFC10 = *(000000013F42CB10) = 5356268064 = -4
Thông báo, cả GCC và VC++ trữ trên stack trong số main
biến địa phương ẩn cho thời gian và MIGHT âm thầm trở lại sử dụng chúng. Mọi thứ diễn ra bình thường, cho đến khi ghi đè thủ công cuối cùng: sau lần ghi đè thủ công cuối cùng, chúng tôi có cuộc gọi riêng biệt bổ sung tới std::cout
. Nó sử dụng không gian ngăn xếp đến nơi chúng tôi vừa viết một cái gì đó, và kết quả là chúng tôi nhận được rác.
Tóm lại: cả GCC và VC++ phân bổ không gian cho thời gian trên ngăn xếp người gọi. Họ có thể có các chiến lược khác nhau về số lượng không gian để phân bổ, cách sử dụng lại không gian này (nó có thể phụ thuộc vào việc tối ưu hóa). Cả hai đều có thể tái sử dụng không gian này theo quyết định của họ và do đó, không an toàn để lấy địa chỉ tạm thời, vì chúng tôi có thể cố gắng truy cập thông qua địa chỉ này mà chúng tôi cho là vẫn có (nói, viết gì đó trực tiếp rồi thử để lấy nó), trong khi trình biên dịch có thể đã sử dụng lại nó và ghi đè giá trị của chúng tôi.
** Liên quan: ** http://stackoverflow.com/questions/4301179/why-is-taking-the-address-of-a-temporary-illegal (mặc dù tôi không hoàn toàn tin rằng nó giống nhau) –
một trong những câu trả lời hoành tráng nhất tại SO áp dụng cho câu hỏi của bạn rất tốt: [Có thể truy cập bộ nhớ của biến cục bộ ngoài phạm vi của nó không?] (Http://stackoverflow.com/a/6445794/1025391) – moooeeeep
MSVS được phép thực hiện bất kỳ tiện ích mở rộng ngôn ngữ nào mà bạn muốn. Tôi đồng ý với bạn rằng nó là lạ, mặc dù. –