[basic.scope.pdecl] / 1 của dự thảo tiêu chuẩn C ++ 20 có ví dụ (không quy định) sau trong một ghi chú (trích dẫn một phần từ trước khi hợp nhất yêu cầu kéo 3580 , xem câu trả lời cho câu hỏi này):
unsigned char x = x;
[...] x được khởi tạo với giá trị (không xác định) của chính nó.
Điều này thực sự có hành vi được xác định rõ trong C ++ 20?
Nói chung, việc tự khởi tạo biểu mẫu T x = x;
có hành vi không xác định do x
giá trị của không xác định trước khi hoàn thành khởi tạo. Đánh giá các giá trị không xác định thường gây ra hành vi không xác định ( [basic.indent] / 2 ), nhưng có một ngoại lệ cụ thể trong [basic.indent] /2.3 cho phép khởi tạo trực tiếp một unsigned char
biến từ một giá trị unsigned char
không xác định (gây ra khởi tạo với giá trị không xác định ).
Do đó, điều này một mình không gây ra hành vi không xác định, nhưng đối với các loại khác T
không phải là loại ký tự hẹp không dấu hoặc std::byte
, ví dụ int x = x;
. Những cân nhắc này được áp dụng trong C ++ 17 và trước đó, xem thêm các câu hỏi được liên kết ở phía dưới.
Tuy nhiên, ngay cả đối với unsigned char x = x;
, bản dự thảo hiện tại [basic.lifetime] / 7 nói:
Tương tự, trước khi thời gian tồn tại của một đối tượng đã bắt đầu [...] bằng cách sử dụng các thuộc tính của giá trị không phụ thuộc vào giá trị của nó được xác định rõ. Chương trình có hành vi không xác định nếu:
glvalue được sử dụng để truy cập vào đối tượng, hoặc
[...]
Điều này dường như ngụ ý rằng x
giá trị trong ví dụ chỉ có thể được sử dụng trong suốt vòng đời của nó.
[basic.lifetime] / 1 nói:
[...]
Thời gian tồn tại của một đối tượng loại T bắt đầu khi:
- [...] Và
- khởi tạo của nó (nếu có) đã hoàn tất (bao gồm cả khởi tạo trống) ([dcl.init]),
[...]
Do đó x
, cuộc đời chỉ bắt đầu sau khi hoàn thành khởi tạo. Nhưng trong x
giá trị của ví dụ được trích dẫn được sử dụng trước khi quá trình x
khởi tạo hoàn tất. Do đó việc sử dụng có hành vi không xác định.
Phân tích của tôi có đúng không và nếu có, nó có ảnh hưởng đến các trường hợp sử dụng trước khi khởi tạo không, chẳng hạn như
int x = (x = 1);
mà theo như tôi có thể nói, được xác định rõ trong C ++ 17 và trước đó thì sao?
Lưu ý rằng trong C ++ 17 (bản nháp cuối cùng), yêu cầu thứ hai để bắt đầu trọn đời là khác nhau :
- nếu đối tượng có khởi tạo không trống, việc khởi tạo của nó hoàn tất,
Vì x
sẽ có khởi tạo trống theo định nghĩa của C ++ 17 (nhưng không phải là khởi tạo trong bản nháp hiện tại), nên thời gian tồn tại của nó đã bắt đầu khi nó được truy cập trong trình khởi tạo trong các ví dụ nêu trên và vì vậy trong cả hai ví dụ không có hành vi không xác định do thời gian tồn x
tại của C ++ 17.
Từ ngữ trước C ++ 17 lại khác, nhưng có cùng kết quả.
Câu hỏi không phải là về hành vi không xác định khi sử dụng các giá trị không xác định, được nêu trong ví dụ: các câu hỏi sau:
int x ^= x;
không được hình thành tốt về mặt cú pháp. Bạn có thể có một định nghĩa biến với trình khởi tạo (nghĩa là int x = x;
mặc dù là UB) hoặc câu lệnh biểu thức gán xor (nghĩa là x ^= x;
mặc dù đó là UB nếu x
thuộc loại int
, được khởi tạo mặc định và không được gán trước). Bạn không thể trộn hai thứ này thành một.