2010-05-12 32 views
20

Giả sử tôi có khai báo cấu trúc sau (cấu trúc đơn giản không có hàm tạo).Cấu trúc thành viên có thể là số không-init từ danh sách khởi tạo hàm tạo không cần gọi bộ nhớ không?

struct Foo 
{ 
    int x; 
    int y; 
    int z; 
    char szData[DATA_SIZE]; 
}; 

Bây giờ chúng ta hãy nói struct này là thành viên của một lớp C++ như sau:

class CFoobar 
{ 
    Foo _foo; 
public: 
    CFoobar(); 
}; 

Nếu Tôi tuyên bố constructor CFoobar như sau:

CFoobar::CFoobar() 
{ 
    printf("_foo = {%d, %d, %d}\n", _foo.x, _foo.y,_foo.z); 
    for (int x = 0; x < 100; x++) 
     printf("%d\n", _foo.szData[x]); 
} 

Như bạn mong đợi, khi CFoobar của nhà xây dựng chạy, dữ liệu rác được in ra Rõ ràng, sửa chữa dễ dàng là để memset hoặc ZeroMemory & _foo. Đó là những gì tôi đã luôn luôn thực hiện ...

Tuy nhiên, tôi đã thông báo rằng nếu thêm _foo vào danh sách khởi tạo của constructor không có tham số như sau:

CFoobar::CFoobar() 
: _foo() 
{ 

Đó này dường như zero-out thành viên biến của _foo. Ít nhất đó là trường hợp với g ++ trên Linux.

Bây giờ, đây là câu hỏi của tôi: Đây có phải là tiêu chuẩn C++ hay hành vi cụ thể của trình biên dịch này không?

Nếu đó là hành vi tiêu chuẩn, ai đó có thể báo cho tôi tham chiếu từ nguồn chính thức không? Bất kỳ "gotchas" liên quan đến hành vi không-init ngầm định với các cấu trúc và lớp phức tạp hơn?

Trả lời

11

Có, đây là hành vi được xác định theo tiêu chuẩn. 12.6.2 [class.base.init]/3: "nếu danh sách biểu hiện của bộ khởi tạo mem bị bỏ qua, lớp cơ sở hoặc đối tượng con của thành viên là giá trị được khởi tạo".

Được cảnh báo, tuy nhiên, nếu Foo không phải là một POD-type nhưng vẫn không có nhà xây dựng sử dụng khai báo (ví dụ nó có một loại std::string) sau đó một số trình biên dịch rất phổ biến sẽ không chính xác giá trị khởi tạo nó.

Tất cả trình biên dịch mà tôi biết thực hiện đúng cách giá trị khởi tạo của thành viên POD khi bạn sử dụng () làm trình khởi tạo trong danh sách khởi tạo hàm dựng.

+0

"một số trình biên dịch phổ biến" = VC6 tôi giả sử? Bởi vì tôi đã không nhìn thấy hành vi sai trong bất kỳ trình biên dịch nào từ 10 năm qua. – MSalters

+0

@MSalters: Và các trình biên dịch VS2005 và VS2008, thật không may. Tôi đã không thử điều này trên VS2010. –

+0

@MSalters: Không chỉ áp dụng cho các thành viên cấu trúc không phải POD mà không có người xây dựng được người dùng khai báo; các loại khác hoạt động chính xác. Có một số báo cáo về điều này trên Connect. Đây là một trong những mà tôi tìm thấy: https://connect.microsoft.com/VisualStudio/feedback/details/484295/vc-does-not-value-initialize-members-of-derived-classes-without-user-declared-constructor –

2

tôi tìm thấy nó khó đọc tiêu chuẩn, nhưng tôi thấy nó tôi nghĩ rằng:

Để giá trị khởi tạo một đối tượng kiểu T có nghĩa là:
nếu T là một loại lớp phi công đoàn mà không có một constructor do người dùng khai báo, sau đó mọi thành phần dữ liệu không tĩnh và thành phần lớp cơ sở- của T được khởi tạo giá trị Khởi tạo giá trị cho đối tượng lớp như vậy có thể được thực hiện bằng cách khởi tạo đối tượng zero và sau đó gọi hàm tạo mặc định.

Mục 8.5

+0

8.5 cần được đọc kết hợp với 12.6.2 để biết rằng trình khởi tạo thành viên này thực sự gọi cho _value-initialization_. –

1

Đó là tương đương với float foo = float();

Nó sẽ bằng không đối tượng, ngay cả khi các đại diện giá trị không phải là tất cả-bit-zero. I E. thậm chí còn tốt hơn là memset().

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