2010-04-30 41 views
40

Xem mã bên dưới. Tôi biết nó không trả về địa chỉ của biến cục bộ, nhưng tại sao nó vẫn hoạt động và gán biến số i trong main() đến '6'? Làm thế nào nó chỉ trả về giá trị nếu biến đã bị xóa khỏi bộ nhớ ngăn xếp?Trả lại tham chiếu đến biến cục bộ hoặc tạm thời

#include <iostream> 

int& foo() 
{ 
    int i = 6; 
    std::cout << &i << std::endl; //Prints the address of i before return 
    return i; 
} 

int main() 
{ 
    int i = foo(); 
    std::cout << i << std::endl; //Prints the value 
    std::cout << &i << std::endl; //Prints the address of i after return 
} 
+19

Bạn thật may mắn. Đừng làm thế. –

+3

Bạn có thể thấy điều này hữu ích: http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – letsc

+0

Tôi tin rằng một số may mắn là trong thực tế rằng tôi là unaltered trong foo() (cho phép các trình biên dịch đặt trong văn bản hoặc một nơi nào đó tồn tại lâu thay vì ngăn xếp) – mho

Trả lời

22

Bạn đã gặp may mắn. Quay trở lại từ chức năng không ngay lập tức xóa khung ngăn xếp bạn vừa thoát.

BTW, làm cách nào bạn xác nhận rằng bạn có 6 lưng? Biểu thức std::cout << &i ... in địa chỉ của i, không phải giá trị của nó.

+3

số 6 xuất hiện khi in nó trong main(). –

+2

@San: Vâng, bây giờ thì @ Dave18 đã chỉnh sửa câu hỏi. –

+1

Xin lỗi, tôi phải đọc câu hỏi sau này :) –

1

Trong khi hàm của bạn trả về một số nguyên bằng tham chiếu, nó được gán ngay cho biến cục bộ 'i' trong main(). Điều đó có nghĩa rằng bộ nhớ stack được cấp phát cho foo() phải tồn tại chỉ đủ lâu cho phép gán trả về. Trong khi đó là hình thức xấu, điều này thường hoạt động. Nếu bạn đã cố gắng giữ một tham chiếu

int &i = foo(); 

nó sẽ có nhiều khả năng bị lỗi hơn.

3

Trả về tham chiếu hoặc con trỏ tới biến cục bộ là hành vi không xác định. Hành vi không xác định có nghĩa là, tiêu chuẩn để lại quyết định cho trình biên dịch. Điều đó có nghĩa là, hành vi không xác định đôi khi hoạt động tốt và sometimes it doesn't.

+4

Và cơ hội không hoạt động tốt tùy thuộc vào tầm quan trọng của những người xem bản demo. – KeithB

2

Địa chỉ của i sẽ không bao giờ thay đổi trong main(), nhưng giá trị chứa trong đó sẽ. Bạn đang lấy tham chiếu của một biến cục bộ và sử dụng nó sau khi tham chiếu đó đã nằm ngoài phạm vi. (Cảnh báo ngôn ngữ hiển thị) Giá trị 6 đang ở trên ngăn xếp. Vì bạn không làm bất cứ điều gì với ngăn xếp sau khi bạn đặt 6 ở đó, tham chiếu đến nó sẽ vẫn chứa cùng một giá trị. Vì vậy, như những người khác đã nói, bạn đã may mắn.

Để xem như thế nào may mắn, hãy thử chạy mã này trong đó sử dụng ngăn xếp sau khi bạn gọi foo():

#include <iostream> 
#include <ctime> 
#include <numeric> 

int& foo() 
{ 
    int i = 6; 
    std::cout << &i << " = " << i << std::endl; //Prints the address of i before return 
    return i; 
} 

long post_foo(int f) 
{ 
    srand((unsigned)time(0)); 

    long vals[10] = {0}; 
    size_t num_vals = sizeof(vals)/sizeof(vals[0]); 
    for(size_t i = 0; i < num_vals; ++i) 
    { 
     int r = (rand()%2)+1; 
     vals[i] = (i+f)*r; 
    } 

    long accum = std::accumulate(vals, &vals[num_vals], 0); 
    return accum * 2; 
} 

int main() 
{ 
    int &i = foo(); 
// std::cout << "post_foo() = " << post_foo(i) << std::endl; 
    std::cout << &i << " = " << i << std::endl; 
} 

Khi tôi chạy này với post_foo() cuộc gọi nhận xét ra, 6 vẫn còn trên stack và đầu ra là:

002CF6C8 = 6 
002CF6C8 = 6 

... nhưng khi tôi bỏ nhận xét cuộc gọi đến post_foo() và chạy nó một lần nữa, 6 đã qua lâu rồi:

001FFD38 = 6 
post_foo() = 310 
001FFD38 = 258923464 
Các vấn đề liên quan