2017-02-03 19 views
21

Tôi biết rằng i=i++; là một hành vi không xác định, bởi vì i được thay đổi hai lần trước điểm chuỗi ;.Có phải hành vi không xác định sau đây không? i = func (i)

Nhưng tôi không biết nếu trình biên dịch đảm bảo trường hợp như dưới đây không phải là một hành vi không xác định:

int func(int &i) 
{ 
    i++; 
    return i; 
} 

int i = 1; 
i = func(i); 
+0

gì trình biên dịch nói? – tristan

+24

@tristan thường, trình biên dịch không nói gì về UB. – user2079303

+0

gcc có tùy chọn '-Sách-điểm' – tristan

Trả lời

44

Thứ nhất, hiện đại, C++ đã chuyển từ cũ (không đầy đủ) khái niệm "điểm chuỗi" để khái niệm mới về "trình tự" (tức là "được sắp xếp trước", "được sắp xếp theo trình tự sau"). Mặc dù i = i++ vẫn chưa được xác định, i = ++i thực sự được xác định hoàn hảo ngay bây giờ. Các quy tắc sắp xếp thứ tự trong nhiều toán tử trả về bằng lvalue đã được làm lại.

Thứ hai, phiên bản của bạn được an toàn theo đặc điểm kỹ thuật cũ cũng như trong phiên bản mới. Việc sửa đổi i bên trong chức năng được "cách ly" một cách an toàn khỏi nhiệm vụ sang i bên ngoài. Trong các điểm chuỗi đặc điểm kỹ thuật cổ điển ở đầu và ở cuối hàm, hãy tách riêng các sửa đổi (và đọc) của i khỏi nhau. Các quy tắc sắp xếp thứ tự mới duy trì cùng mức độ bảo vệ.

Một ví dụ minh họa việc bảo vệ được cung cấp bởi một cuộc gọi chức năng có thể trông như sau

int inc(int &i) { return i++; } 
... 
int i = 1; 

int r1 = i++ * i++ * i++;   
// Undefined behavior because of multiple unsequenced side effects 
// applied to the same variable 

int r2 = inc(i) * inc(i) + inc(i); 
// No UB, but order of evaluation is unspecified. Since the result 
// depends on the order of evaluation, it is unspecified 

int r3 = inc(i) + inc(i) + inc(i); 
// Perfectly defined result. Order of evaluation is still unspecified, 
// but the result does not depend on it 
+0

"Việc sửa đổi của tôi bên trong chức năng là một cách an toàn" bị cô lập "từ việc giao cho tôi bên ngoài." Điều gì nếu trình biên dịch inlines chức năng? Hoặc có tiềm năng cho UB có nghĩa là trình biên dịch sẽ không inline trường hợp cụ thể này? – JAB

+4

@JAB: Nội tuyến không theo bất kỳ cách nào thay đổi ngữ nghĩa thứ tự (hoặc bất kỳ ngữ nghĩa nào khác) của một cuộc gọi hàm. Trình biên dịch là miễn phí để nội tuyến bất cứ điều gì nó muốn bất cứ lúc nào, nhưng mã kết quả phải bảo toàn đầy đủ ngữ nghĩa trừu tượng ban đầu. I E. hành vi của cuộc gọi nội tuyến phải giống như hành vi của cuộc gọi không được nội tuyến. Không có gì trong trường hợp này để ngăn chặn trình biên dịch từ nội tuyến. Nhưng trình biên dịch phải nhớ rằng phiên bản nội tuyến phải bảo toàn hoàn toàn hành vi của một không được nội tuyến. – AnT

+0

Điều đó tốt, vì tôi đã lợi dụng loại hành vi đó trong quá khứ. – JAB

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