2009-11-21 36 views
8

Trong đoạn mã sau đây, bộ khởi tạo d1 được truyền d2 chưa được xây dựng (đúng?), Do đó, d.j trong bộ tạo bản sao của D là truy cập bộ nhớ chưa được khởi tạo?Thứ tự khởi tạo có được đảm bảo theo tiêu chuẩn không?

struct D 
{ 
    int j; 

    D(const D& d) { j = d.j; } 
    D(int i) { j = i; } 
}; 

struct A 
{ 
    D d1, d2; 
    A() : d2(2), d1(d2) {} 
}; 

Phần nào của tiêu chuẩn C++ thảo luận thứ tự khởi tạo thành viên dữ liệu?

+0

Liên quan mặc dù không trùng lặp câu hỏi: http://stackoverflow.com/questions/1589950/initializer-list-argument-evaluation-order –

Trả lời

11

Tôi không có tiện ích chuẩn ngay bây giờ để tôi không thể báo giá phần, nhưng cấu trúc hoặc thành viên lớp học initialisation luôn luôn xảy ra theo thứ tự đã khai báo. Thứ tự mà các thành viên được đề cập trong danh sách khởi tạo của hàm dựng không có liên quan.

Gcc có một cảnh báo -Wreorder rằng cảnh báo khi đơn đặt hàng khác:

 
     -Wreorder (C++ only) 
      Warn when the order of member initializers given in the code does 
      not match the order in which they must be executed. For instance: 

        struct A { 
        int i; 
        int j; 
        A(): j (0), i (1) { } 
        }; 

      The compiler will rearrange the member initializers for i and j to 
      match the declaration order of the members, emitting a warning to 
      that effect. This warning is enabled by -Wall. 
+5

Lý do cho điều này là mọi thứ bị hủy theo thứ tự ngược lại chúng được xây dựng. Bạn không thể thay đổi thứ tự các thành viên bị hủy sau khi destructor, do đó lệnh được xây dựng * phải * tương ứng. – GManNickG

+2

Tuy nhiên, bạn vẫn có thể tham khảo các thành viên đã được khởi tạo trước đó, như được thảo luận tại đây: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.7 – Jherico

+1

Giải thích FAQ trong trường hợp này khá hữu ích, Tôi nghĩ; tiêu chuẩn nói "có một điểm chuỗi sau khi khởi tạo của mỗi cơ sở và thành viên" (12.6.2/3). –

1

Yes. Trình biên dịch tốt sẽ cảnh báo bạn rằng A::d2 sẽ được khởi tạo sau A::d1.

6

Trong ví dụ của bạn nó sẽ thất bại:

struct A 
{ 
    D d1, d2;  
    A() : d2(2), d1(d2) {} 
}; 

d1: is initialised first as it is declared first. 
d2: is then initialized. 

Kết quả là danh sách initializer sẽ xây dựng d1 sử dụng một tham chiếu đến một đối tượng không hợp lệ (d2).

Đây là một lý do để bật lên mức cảnh báo trình biên dịch của bạn ở mức cao nhất có thể.
Và bổ sung buộc phải báo cáo tất cả các cảnh báo là lỗi.

2

Hiện tượng này được giải thích/được nêu bật trong Mục 13 của Meyer Hiệu quả C++. Nó nói rằng hàm hủy phải phá hủy các phần tử theo thứ tự ngược của các hàm tạo của nó, do đó tất cả các hàm khởi tạo phải khởi tạo các phần tử theo cùng thứ tự, do đó chúng khởi tạo chúng theo thứ tự mà chúng được khai báo (thay vì chuỗi các danh sách khởi tạo) .

11

Tiêu chuẩn C++ (ISO/IEC 14882: 2003 12.6.2/5, Khởi tạo các căn cứ và các thành viên) nói:

Khởi tạo sẽ tiến hành theo trình tự sau:

- Thứ nhất, và chỉ dành cho hàm tạo của lớp dẫn xuất nhất như được mô tả bên dưới, các lớp cơ sở ảo phải được khởi tạo theo thứ tự chúng xuất hiện trên một chiều ngang trái-phải-phải của biểu đồ tuần hoàn trực tiếp của các lớp cơ sở, trong đó “left-to -ngắn ”là thứ tự xuất hiện của tên lớp cơ sở trong cơ sở lớp có nguồn gốc r-danh sách.

- Sau đó, các lớp cơ sở trực tiếp sẽ được khởi tạo theo thứ tự khai báo khi chúng xuất hiện trong danh sách-specifier-list (bất kể thứ tự của bộ khởi tạo mem).

- Sau đó, các thành viên dữ liệu không tĩnh sẽ được khởi tạo theo thứ tự chúng được khai báo trong định nghĩa lớp (một lần nữa bất chấp thứ tự của bộ khởi tạo mem).

- Cuối cùng, phần thân của hàm tạo được thực hiện.

Điểm bullet 3 đảm bảo thứ tự khởi tạo thành viên dữ liệu phi tĩnh.

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