2012-06-25 56 views
25

thể trùng lặp:
int var = 1; void main() { int i = i; }Tại sao 'int i = i;' hợp pháp?

Các mã sau đây có thể vượt qua biên soạn theo cả hai g ++ và Visual C++. Tại sao nó hợp pháp? Có vẻ không hợp lý và có thể gây ra lỗi ẩn.

int main() { 
    int i = i; 
} 
+7

Đối với tôi nó không phải là bất hợp pháp, nó chỉ là một sự lạm dụng ký hiệu. –

+8

Nó đánh giá là (i) 'int i' (ii)' i = i' theo thứ tự đó –

+0

Tôi nghĩ cùng một lý do mà chỉ 'int i;' mà không bao giờ gán 'i' là hợp pháp. – asmeurer

Trả lời

42

EDIT: Đó là cú pháp pháp lý, nhưng kết quả trong hành vi undefined nếu bạn sử dụng x.

Đó là không phải hợp pháp vì bạn chỉ định biến chưa được khởi tạo với biến khác (tốt, giống nhau) chưa được khởi tạo. Chỉ vì nó biên dịch không có nghĩa là nó hợp pháp. Đó là cú pháp C++ hợp lệ, có, nhưng không hợp pháp.

Phía bên tay phải của toán tử gán phải được đánh giá đầy đủ tại thời điểm gán. Trong trường hợp này, đó là i, không được khởi tạo.

Tín dụng cho Steve Jessop, người đào lên báo giá:

4,1/1, giá trị trái-to-rvalue chuyển đổi

[...] nếu đối tượng chưa được định hình, một chương trình yêu cầu chuyển đổi này có hành vi không xác định.

+0

Đối số đó là hình tròn, có một biến có giá trị là không xác định chắc chắn không phải là bất hợp pháp. So sánh nó với 'int i;' đơn giản, nó cũng để lại 'i' với giá trị không xác định. – unwind

+0

@nhahtdh không có nghĩa là nó hợp pháp. –

+0

Luchian, nó biên dịch, và không có gì trong spec mà không cho phép nó. – OmnipotentEntity

7

Bạn có thể để g++ cảnh báo bạn về trường hợp sử dụng này với -Winit-self (kết hợp với -Wuninitialized), và nếu bạn đối xử với cảnh báo là lỗi, nó phải đáp ứng ngứa của bạn.

Kỹ thuật này bằng cách sử dụng hàm tạo bản sao để tự khởi tạo đôi khi được sử dụng để ngăn chặn hàm khởi tạo mặc định của đối tượng toàn cục/khởi tạo từ thực thi. Điều này có thể cần thiết nếu hàm tạo mặc định của đối tượng toàn cầu chỉ là để 0 khởi tạo đối tượng, nhưng đối tượng đã được sử dụng trước khi hàm tạo sẽ được thực hiện. Như một sự trở lại cho C, globals được 0 khởi tạo lúc bắt đầu chương trình, và sau đó thời gian chạy C++ bắt đầu thực hiện các hàm tạo chung. Đối với những trường hợp hẹp mà các nhà xây dựng được xác định mà có thể đã thực hiện chỉ để 0 ra các đối tượng, tự khởi tạo không làm bất kỳ tác hại. Trong trường hợp chung, sao chép khởi tạo tự khởi tạo là thực hành không tốt, vì nó thường sẽ gây ra cùng một loại vấn đề mà sử dụng một biến chưa được khởi tạo sẽ gây ra (đó là, hành vi không xác định). Trong ví dụ cụ thể trong câu hỏi của OP, i là địa phương để main và do đó chưa được khởi tạo. Kết quả của việc đọc một biến chưa được khởi tạo luôn là hành vi không xác định.

+0

Dường như nó không tạo ra bất kỳ cảnh báo nào với '-Winit-self' cho tôi. – nhahtdh

+0

@nhahtdh: Cảm ơn, tôi đã cập nhật bài đăng. Kính trọng – jxh

+0

_If_ đối tượng có kiểu do người dùng xác định và hàm tạo sẽ lấy cá thể bằng tham chiếu và không bao giờ dereferences nó (trong hàm tạo), sau đó mã là hợp pháp. (Ví dụ, hàm tạo của người dùng có thể lưu địa chỉ) –

14

Lý do nó được cho phép bởi cú pháp là có một số trường hợp lẻ nơi bạn có thể hình dung muốn sử dụng một biến bởi con trỏ hoặc tham chiếu trong initializer riêng của mình:

struct ThingManager { 
    void *thing; 
    ThingManager(void *thing) : thing(thing) {} 
    void Speak() { 
     if (thing == (void*)this) { 
      std::cout << "I'm managing myself\n"; 
     } else { 
      std::cout << "I'm managing " << thing << "\n"; 
     } 
    } 
}; 

ThingManager self_manager(&self_manager); 
ThingManager other_manager(&self_manager); 

Vì vậy, C++ cho phép bạn tham khảo một đối tượng trong biểu thức khởi tạo riêng của nó (tên của nó nằm trong phạm vi).Sau đó, bao giờ hết trong C + +, đó là vấn đề của bạn để chắc chắn rằng bạn không thực sự sử dụng một giá trị uninitialized (ví dụ của bạn, int i = i; không sử dụng một giá trị uninitialized).

Trình biên dịch có thể giúp xác định việc sử dụng các giá trị chưa được khởi tạo, nhưng tiêu chuẩn không yêu cầu nó.

2

Bạn có thể sử dụng bất kỳ biến được khai báo trước đây nào làm trình khởi tạo của biến khác.

Trong trường hợp này ngay sau khi trình biên dịch phân tích cú pháp int i, nó thêm vào bảng biểu tượng, vì vậy khi nó thấy trình khởi tạo = i, biểu tượng có thể được giải quyết từ tuyên bố trước đó. Đây không phải là lỗi bởi vì trình biên dịch có thể hiểu được nó ở chỗ nó có thể tạo mã rõ ràng làm chính xác những gì mã nguồn chỉ định, bảy nếu nó là nghi ngờ ngữ nghĩa. Triết lý của C và C++ là biên dịch bất cứ thứ gì có thể được biên dịch theo cú pháp. Lỗi ngữ nghĩa thường chỉ phát hành cảnh báo và chỉ khi đó các cảnh báo như vậy được bật.

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