2013-08-17 35 views
7

Tôi thường xuyên đi qua cấu trúc POD trong mã được bằng tay zero-khởi tạo với memset như vậy:trong C++ 11, bạn luôn có thể (an toàn) thay thế một khởi tạo memset() bằng một bộ khởi tạo trống không?

struct foo; 
memset(&foo, 0, sizeof(foo)); 

Tôi đã kiểm tra các tiêu chuẩn C++ 11 và nó nói: "Một đối tượng có initializer là một tập rỗng của dấu ngoặc đơn, tức là,(), sẽ được khởi tạo giá trị. "Được theo sau bởi:"Để giá trị khởi tạo [cấu trúc nhóm] của loại T có nghĩa là ... đối tượng không được khởi tạo."

... Vì vậy, điều này có nghĩa là bạn có thể luôn an toàn ngưng tụ mã ở trên để chỉ sau:

struct foo{}; 

Và có một cấu trúc khởi tạo được bảo đảm, nếu như bạn đã gọi memset(&foo, 0, ...)?


Nếu vậy, sau đó nói chung, có thể giúp bạn một cách an toàn khởi tạo bất cứ điều gì với initializers trống như vậy:

SomeUnknownType foo{}; // will 'foo' be completely "set" to known values? 

Tôi biết điều này không phải luôn luôn có thể trong C++ 03 (trước uniform initialization syntax) nhưng có thể bây giờ trong C++ 11 cho bất kỳ loại nào không?

+2

kiểm tra chủ đề này: http://stackoverflow.com/questions/620137/do-the-parentheses-after-the-type-name-make-a-difference-with-new câu trả lời chung là có. –

+1

Xin lưu ý rằng MSVC chưa bao giờ hỗ trợ khởi tạo giá trị đúng cách và sẽ không thành công trong một số ngữ cảnh. [Microsoft dường như không quan tâm đến việc sửa lỗi] (http://connect.microsoft.com/VisualStudio/feedback/details/484295). – Casey

+0

@Casey: Đó là một lỗi khá nghiêm trọng, tôi tự hỏi nếu nó đã được sửa trong VS mới nhất. May mắn thay, tôi sử dụng gcc và clang (mà dường như quan tâm đến việc tuân thủ các tiêu chuẩn) và mã của tôi không ** phải được chuyển sang các trình biên dịch khác hoặc thậm chí các phiên bản cũ hơn của gcc hoặc clang. – MikeTusar

Trả lời

8

Bạn chắc chắn có thể khởi tạo bất kỳ loại bố cục chuẩn nào bằng cách sử dụng dấu ngoặc đơn trống và làm cho nó không được khởi tạo. Khi bạn thêm nhà xây dựng thành bức tranh, điều này không hẳn đã đúng, không may:

struct foo { 
    int f; 
}; 
struct bar { 
    int b; 
    bar() {} 
}; 

foo f{}; 
bar b{}; 

Trong khi f.f là zero khởi tạo, b.b chưa được định hình. Tuy nhiên, bạn không thể làm bất cứ điều gì về số bar vì bạn cũng không thể memset(). Nó cần được sửa chữa.

+0

Vì vậy, để tóm tắt, bất cứ nơi nào 'memset()' một cách an toàn có thể được sử dụng để khởi tạo một loại, do đó, có thể khởi tạo rỗng (ngoặc/niềng răng) để đạt được zero-initialization của bộ nhớ ... chính xác? – etherice

+1

@etherice: Đúng. 'memset()' chỉ có thể được sử dụng trên POD và POD luôn được khởi tạo bằng không. Điều đó nói rằng, điều này áp dụng cho tất cả các thành viên. Tôi không nghĩ rằng dấu ngoặc đơn trống/niềng răng thực hiện bất kỳ đảm bảo về padding. Nó không nên quan trọng nhưng đôi khi nó làm. –

+0

Chúng làm cho '{}' được khởi tạo tổng hợp thay vì initializatio giá trị cho một cấu trúc tổng hợp. Không khởi tạo và do đó cho việc tổng hợp giá trị khởi tạo đảm bảo rằng padding là số không. Nhưng tôi không tin rằng khởi tạo tổng hợp. –

3

Bộ nhớ sẽ khởi tạo nó thành 0 nhưng dấu ngoặc đơn trống sẽ có giá trị khởi tạo đối tượng của bạn (có sự khác biệt).

Trích dẫn từ tiêu chuẩn:

Để 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 với một constructor do người dùng khai báo, sau đó các nhà xây dựng mặc định cho T là được gọi (và khởi tạo bị hỏng nếu T không có hàm tạo mặc định có thể truy cập);

Ngoài ra, làm struct foo{}; an toàn và không cần phải đặt lại con trỏ bảng ảo.

Nhưng thực hiện memset(&foo, 0, sizeof(foo)); trong trường hợp các chức năng ảo thực sự rất tệ vì nó đặt lại con trỏ vào bảng ảo.

+1

Nếu có hàm 'virtual' trong' foo' bằng cách sử dụng 'memset()' trên một đối tượng dẫn đến hành vi không xác định. Bạn chỉ có thể 'memset()' một số loại nhất định. Chúng thường được gọi là POD (dữ liệu cũ) nhưng tôi nghĩ chúng được gọi là một cái gì đó khác trong C++ 11. –

+0

@ DietmarKühl Cảm ơn thông tin hữu ích. Chỉ mới bắt đầu học. Bất kỳ ý kiến ​​hữu ích khác cho câu trả lời của tôi sẽ rất hữu ích. – Saksham

+0

@ DietmarKühl, C++ 11 vẫn sử dụng POD, trừ khi ý nghĩa thay đổi và đó là một thuật ngữ khác mà bạn đang nghĩ đến cho những gì từng là POD. – chris

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