2016-02-10 34 views
5

dụ đầu tiênTại sao hai ví dụ tham chiếu rvalue này lại có hành vi khác nhau?

int a = 0; 
auto && b = ++a; 
++a; 
cout << a << b << endl; 

in 22

dụ thứ hai

int a = 0; 
auto && b = a++; 
++a; 
cout << a << b << endl; 

in 20

Câu hỏi: Tại sao trong ví dụ đầu tiên ++a trong dòng thứ ba cũng tăng b và tại sao không có hành vi như vậy trong ví dụ thứ hai?

Cập nhật:New question phát sinh.

+0

Tôi sẽ cung cấp cho bạn một gợi ý - 'a' không phải là một giá trị. – erip

+0

@erip Vâng, tôi biết, nhưng sự khác biệt trong hai ví dụ cho 'b' là gì? – vladon

+0

Trong ví dụ thứ hai 'b' nhận giá trị' a' mà không tăng giá trị trước đó, như trong ví dụ đầu tiên. – x13

Trả lời

10

Bởi vì trước increment (++a) đầu tiên tăng giá trị của a, lưu trữ kết quả, và sau đó trả về tham chiếu đến a. Bây giờ ab có hiệu quả trỏ đến cùng một đối tượng.

Tăng sau (a++), tuy nhiên, trước tiên hãy lưu trữ giá trị hiện tại là a theo tạm thời, tăng a và trả lại tạm thời này - điểm ref trị giá trị của bạn. ab trỏ đến các đối tượng khác nhau, cụ thể hơn - b tạm thời giữ giá trị a trước khi tăng.

Đây là lý do tại sao nó được khuyến khích sử dụng ++it qua it++ cho vòng lặp và các đối tượng phức tạp khác mà xác định tăng/giảm: sau này sẽ tạo ra một bản sao tạm thời và do đó có thể thể chậm hơn.

+0

UB có sử dụng 'b' sau' a ++' trong ví dụ thứ hai không? – vladon

+0

Và tại sao trong trường hợp đầu tiên không có tạm thời? Tại sao 'auto && b = a ++' không tương đương với 'auto && b = a; a ++ '? – vladon

+0

@vladon: Tôi _think_ rằng tạm thời sẽ tồn tại cho đến khi tham chiếu đến nó đi ra khỏi phạm vi, có nghĩa là nó không UB, nhưng tôi không chắc chắn. –

1

Trong trường hợp thứ hai (post-increment) b thực sự tham chiếu tới tạm thời được tạo cho (a ++), do đó số gia tăng không ảnh hưởng đến b.

2

Sự khác biệt là ++a là một giá trị, tuy nhiên a++ thì không. Đây được xác định bởi C++ 14 [expr.pre.incr]/1:

Các toán hạng của tiền tố ++ được sửa đổi bằng cách thêm 1 [...] Các toán hạng phải là một giá trị trái sửa đổi. [...] Kết quả là toán hạng được cập nhật; đó là một giá trị trái

và [expr.post.incr]/1:

[...] Kết quả là một prvalue.


Bây giờ chúng ta xem xét auto && b = ++a;. ++a là một lvalue. auto&& là tham chiếu chuyển tiếp. Tham chiếu chuyển tiếp thực sự có thể liên kết với các giá trị: auto có thể tự suy ra một loại tham chiếu. Mã này khấu trừ thành int &b = ++a;.

Khi tham chiếu được liên kết với một giá trị cùng loại, tham chiếu sẽ liên kết trực tiếp, vì vậy b sẽ trở thành một tên khác cho a.


Trong ví dụ thứ hai, là giá trị chính xác. Điều này có nghĩa là nó không có địa chỉ liên quan và nó không còn liên quan đến biến số a. Dòng này có cùng một hành vi như ++a; auto && b = (a + 0);.

Thứ nhất, kể từ a++ là giá trị gia tăng, auto&& khấu trừ thành int&&. (ví dụ: auto khấu trừ thành int). Khi một tham chiếu của loại không phải lớp được ràng buộc với một giá trị, một đối tượng tạm thời được sao chép-khởi tạo từ giá trị. Đối tượng này đã kéo dài tuổi thọ của nó để khớp với tham chiếu.

Vì vậy, b trong trường hợp thứ hai được liên kết với một đối tượng khác từ a, int "tạm thời" (không thực sự quá tạm thời, vì nó kéo dài miễn là b).

Quy tắc ràng buộc tham chiếu nằm trong [dcl.init.ref].

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