2016-06-09 54 views
5

Tôi biết rằng tham chiếu không mất bất kỳ bộ nhớ nào mà nó sẽ trỏ đến cùng một vị trí bộ nhớ mà nó đang tham chiếu. cho ví dụBiến tham chiếu ở đâu được lưu trữ

int i=10; 
int &r = a; 

giả sử i điểm đến vị trí bộ nhớ 1000 như vậy trong trường hợp này r cũng sẽ chỉ đến vị trí bộ nhớ 1000. Nhưng trong C++ khi đã bao giờ chúng ta đang khai báo một biến ý chí của nó được lưu trữ trong bộ nhớ tại một số địa điểm. Trong trường hợp này, r trỏ đến một số vị trí nhưng nó phải được lưu trữ ở đâu đó trong bộ nhớ như là biểu diễn bên trong chỉ sử dụng tham chiếu đến con trỏ const. cảm ơn trước.

+2

Nếu r là một biến, địa chỉ của r là & r. Nó không phải là một tham chiếu, C không phải là C++. Vì vậy, nếu r = & a, & r đại diện cho địa chỉ nơi địa chỉ của một kho được lưu trữ. – Tim

+0

'Biến tham chiếu được lưu trữ ở đâu 'Đây là không xác định. –

Trả lời

6

Điều đó không được chỉ định và vì lý do chính đáng. Câu trả lời thực sự là: nó phụ thuộc vào tham chiếu. Nó có thể được biểu diễn như một con trỏ bình thường, hoặc nó có thể không tồn tại chút nào.

Nếu bạn có một tài liệu tham khảo chức năng địa phương với thời hạn lưu trữ tự động, chẳng hạn như r này:

void foo() 
{ 
    int x[4] = {0, 1, 2, 3}; 
    int &r = x[1]; 
    // more code 
} 

sau đó nó có thể sẽ không mất bất kỳ không gian nào cả. Trình biên dịch sẽ chỉ xử lý tất cả việc sử dụng r làm bí danh cho x[1] và truy cập trực tiếp vào số int. Lưu ý rằng các tham chiếu kiểu bí danh như vậy cũng có thể là kết quả của hàm nội tuyến. Mặt khác, nếu tham chiếu là "liên tục" hoặc hiển thị với các đơn vị dịch khác (chẳng hạn như thành viên dữ liệu hoặc biến toàn cầu), nó phải chiếm một số không gian và được lưu trữ ở đâu đó. Trong trường hợp đó, nó rất có thể sẽ được biểu diễn như một con trỏ, và mã sử dụng nó sẽ được biên dịch thành dereference con trỏ đó.

Về mặt lý thuyết, các tùy chọn khác cũng sẽ có thể (chẳng hạn như bảng tra cứu), nhưng tôi không nghĩ rằng các tùy chọn đó được sử dụng bởi bất kỳ trình biên dịch thực tế nào.

1

Tôi biết tài liệu tham khảo mà không mất bất kỳ bộ nhớ

Không chính xác. Cho dù tham chiếu có bộ nhớ, không được chỉ định. Nó có thể hoặc nó có thể không. Trong ví dụ cụ thể này, nó không cần lưu trữ, do đó, trong một triển khai điển hình, nó không sử dụng bất kỳ.

nó sẽ trỏ đến vị trí nhớ cùng mà nó được tham khảo

Đó có vẻ là một lặp lại không cần hoặc chỉ đơn giản là một sự hiểu lầm, tùy thuộc vào những gì bạn có nghĩa là bởi "điểm". Tham chiếu đề cập đến đối tượng hoặc là bị ràng buộc cho đối tượng. Bạn có thể coi đó là bí danh của tên biến. Tên biến không sử dụng bất kỳ bộ nhớ nào.

Trong trường hợp này r được trỏ đến một số vị trí nhưng nó phải được lưu trữ ở đâu đó trong ký ức

Nó không cần phải được lưu trữ trong bộ nhớ.Hãy xem xét đoạn mã sau:

int i=10; 
int &r = a; 
int j = r * 3; 

Trình biên dịch có thể giải thích r * 3 như i * 3 như nếu bạn đã viết như vậy trong những nơi đầu tiên. Vị trí của đối tượng được giới thiệu được biết ở thời gian biên dịch, vì vậy không cần phải lưu trữ địa chỉ trong bộ nhớ là một điều thời gian chạy.

Nhưng, trong các trường hợp khác, có thể cần phải lưu trữ. Ví dụ: Hãy xem xét một đối số tham chiếu của một hàm không nội tuyến có liên kết bên ngoài. Đối tượng được giới thiệu không thể được biết khi hàm được biên dịch, vì vậy một số thông tin phải được truyền trong bộ nhớ, tại thời gian chạy.

như đại diện nội bộ về const sử dụng tài liệu tham khảo con trỏ chỉ

Đó không phải là chính xác. Các đại diện nội bộ có thể sử dụng một con trỏ, hoặc nó có thể sử dụng cái gì khác, hoặc nó có thể không cần phải sử dụng bất cứ điều gì.

Vì vậy, để chính xác trả lời

đâu biến tài liệu tham khảo được lưu trữ

Đó là không xác định. Hoặc là hư không, hoặc ở đâu đó.

0

gì tiêu chuẩn nói:

Đó là không xác định có hay không một tài liệu tham khảo cần lưu trữ (3.7).

(C++ 11, [dcl.ref] ¶4)

Điều này có nghĩa rằng trình biên dịch là tự do lựa chọn trên cơ sở mỗi hợp cụ thể có hay không có lưu trữ là bắt buộc.

Bây giờ, hãy để mọi người nói những gì họ muốn, nhưng tài liệu tham khảo đun sôi xuống đường cú pháp cho con trỏ (ngay cả ở cấp trình biên dịch, trong tất cả các trình biên dịch C++ chính, khái niệm "tham chiếu" biến mất gần như ngay sau giao diện); do đó, trong trường hợp chung, chúng có thể cần không gian của chúng trong bộ nhớ, giống như con trỏ. Tuy nhiên, trong các trường hợp như của bạn (tham khảo cục bộ) trình biên dịch sẽ xem qua chúng và tối ưu hóa chúng khi cần thiết. Tuy nhiên, thông báo tuy nhiên đây không phải là một tham chiếu độc quyền - trình biên dịch có thể thực hiện cùng một kiểu tối ưu này ngay cả thông qua con trỏ (khi mã của bạn đi theo dạng SSA, không có gì đặc biệt về thực tế là các tham chiếu không thể được lặp lại).

này:

int glob; 

void direct() { 
    glob = 16; 
} 

void through_reference() { 
    int &a = glob; 
    a = 16; 
} 

void through_pointer() { 
    int *a = &glob; 
    *a = 16; 
} 

nắm luôn cùng mã trên bất kỳ trình biên dịch tôi đã cố gắng trên gcc.godbolt.org - example:

direct(): 
     mov  DWORD PTR glob[rip], 16 
     ret 
through_reference(): 
     mov  DWORD PTR glob[rip], 16 
     ret 
through_pointer(): 
     mov  DWORD PTR glob[rip], 16 
     ret 
glob: 
     .zero 4 

Mặt khác, tình hình trở nên một bit trơn hơn khi nói về cấu trúc; ở đây trình biên dịch được phép loại bỏ các tham chiếu khỏi bố cục thực tế của cấu trúc (nếu nó có thể tái tạo lại những gì chúng thực sự trỏ tới), trong khi cho con trỏ tình hình có thể phức tạp hơn một chút. đồ đạc).

Trong thực tế, tôi chưa bao giờ thực sự thấy loại tối ưu hóa này được triển khai trong bất kỳ trình biên dịch thực tế nào. Hãy gcc hoặc MSVC hoặc Clang hoặc bất cứ điều gì và bạn sẽ luôn luôn thấy rằng kích thước struct sẽ đi ra bằng even in the most trivial cases.

0

như đại diện nội bộ về const sử dụng tài liệu tham khảo con trỏ chỉ

Trong trường hợp bạn đã nghe thấy không? Điều đó không đúng.

Tiêu chuẩn không chỉ định cách tham chiếu được triển khai.

Sau đây là quá đơn giản

Phổ biến nhất, trình biên dịch có nội một bảng biểu tượng mà nó lưu trữ tất cả các thông tin cần thiết về các biến.

Chúng ta hãy một trường hợp đơn giản:

int a; 
a = 100; 

sau đó trình biên dịch có thể có một cái gì đó như thế này (vì đơn giản cho phép làm cho địa chỉ của a một địa chỉ cố định gọi)

| identifier | type | address | 
|------------|------|----------| 
| a   | int | 0xFF00A4 | 

Sau đó, nó có thể dịch mã C++ vào một cái gì đó như thế này:

mov 0xFF00A4, 100 

Hãy để ' s thêm một tài liệu tham khảo trong hỗn hợp:

int a; 
a = 100; 
int& ra = 300; 

Bảng biểu tượng trình biên dịch có:

| identifier | type | address | 
|------------|------|----------| 
| a   | int | 0xFF00A4 | 
| ra   | int& | 0xFF00A4 | 

Hoặc:

| identifier | type | address | alias | 
|------------|------|----------|-------| 
| a   | int | 0xFF00A4 | -  | 
| ra   | int& | -  | a  | 

Và do đó có thể tạo ra mã như thế này:

mov 0xFF00A4, 100 
mov 0xFF00A4, 300 

Khi bạn có đối số tham chiếu trong hàm, khi đó một con trỏ được chuyển nội bộ.

+0

Điều này không dành riêng cho tài liệu tham khảo; trình biên dịch thường xuyên thực hiện loại tối ưu hóa này ngay cả trên các con trỏ, một khi mọi thứ có trong biểu mẫu SSA thực sự không có sự khác biệt. –

Các vấn đề liên quan