2010-06-30 41 views
10
typedef struct foo 
{ 
    bool my_bool; 
    int my_int; 
} foo; 

Trong ví dụ trên, chúng tôi hiểu rằng my_bool sẽ được khởi tạo một cách ngẫu nhiên để đúng hoặc sai nhưng những gì về my_int? Tôi giả định rằng my_int sẽ được khởi tạo mặc định thành 0 nhưng điều đó có vẻ không đúng.typedef struct: Khởi Mặc định

cấu trúc Xác định theo cách này dường như là không tương thích với các danh sách khởi tạo vì vậy cách tốt nhất để khởi my_boolmy_int false và 0 tương ứng là bao nhiêu?

+2

Bạn có chắc chắn đây là C++ không? –

+0

@Noah: Không có 'bool' trong C. Nhưng bạn vẫn có điểm. – sbi

+2

"my_bool sẽ được khởi tạo ngẫu nhiên thành true hoặc false" - có thể, nhưng không nhất thiết. Uninitialized có nghĩa là không được khởi tạo ở tất cả. Tùy thuộc vào những gì bạn đang thực hiện, bộ nhớ cho đối tượng được cho phép, ví dụ như chứa một cái bẫy hoặc giá trị không hợp lệ khác. Sự khác biệt là nếu bạn có một giá trị boolean "ngẫu nhiên" 'x' (đúng hoặc sai), thì kết quả của' x || x' được đảm bảo đúng theo tiêu chuẩn. Nếu bạn lấy giá trị boolean chưa được khởi tạo 'y' thì tiêu chuẩn không nói gì về kết quả của' y || y'. Nó có thể đúng, sai hoặc gây ra sự cố hoặc bất kỳ hành vi nào khác. –

Trả lời

18

Các loại không được "khởi tạo". Chỉ đối tượng của một số loại được khởi tạo. Cách thức và thời điểm chúng được khởi tạo phụ thuộc vào cách thức và vị trí của đối tượng tương ứng được xác định. Bạn không cung cấp định nghĩa của bất kỳ đối tượng nào trong câu hỏi của bạn, do đó, câu hỏi của bạn tự nó không thực sự có ý nghĩa nhiều - nó thiếu bối cảnh cần thiết.

Ví dụ, nếu bạn xác định một đối tượng tĩnh của loại foo

static foo foo_object; // zeros 

nó sẽ được tự động zero-khởi tạo bởi vì tất cả các đối tượng với thời gian tĩnh luôn tự động zero-khởi tạo.

Nếu bạn xác định một đối tượng tự động loại foo mà không có một khởi tạo, nó sẽ vẫn chưa được khởi tạo

void func() 
{ 
    foo foo_object; // garbage 
} 

Nếu bạn xác định một đối tượng tự động loại foo với một initializer tổng hợp, nó sẽ được khởi tạo theo với điều đó initializer

void func() 
{ 
    foo foo_object1 = { 1, 2 }; // initialized 
    foo foo_object2 = {}; // initialized with zeros 
} 

Nếu bạn phân bổ đối tượng của bạn với new và cung cấp không khởi tạo, nó sẽ vẫn chưa được khởi tạo

foo *p = new foo; // garbage in `*p` 

Nhưng nếu bạn sử dụng () initializer, nó sẽ là zero-initialzed

foo *p = new foo(); // zeros in `*p` 

Nếu bạn tạo một đối tượng tạm thời loại foo sử dụng biểu thức foo(), kết quả của biểu thức đó sẽ là zero- được khởi tạo

bool b = foo().my_bool; // zero 
int i = foo().my_int; // zero 

Vì vậy, một lần nữa, trong trường hợp cụ thể của bạn, chi tiết khởi tạo phụ thuộc vào bây giờ bạn tạo đối tượng thuộc loại của bạn chứ không phải trên chính loại của bạn. Bản thân loại của bạn không có cơ sở khởi tạo vốn có và không can thiệp vào việc khởi tạo theo bất kỳ cách nào.

+0

Tôi thường tạo một đối tượng tự động bằng cách đơn giản là 'foo a_foo;' ..và sau đó theo dõi với 'a_foo.my_bool = true;' Với các cấu trúc lớn hơn, tôi không luôn muốn đặt thành viên 5-6 thành viên một cách thủ công. –

11

Trước hết, cách mà struct được khai báo là trong phong cách của C. Trong C++ bạn chỉ nên làm:

struct foo 
{ 
    bool my_bool; 
    int my_int; 
}; 

Trong cả hai C và C++, khởi tạo là một bước tách biệt với phân bổ. Nếu bạn luôn muốn khởi tạo các thành viên của struct của bạn, cú pháp khởi tạo sử dụng mặc định như thế này:

struct foo 
{ 
    bool my_bool{}; 
    bool my_int{}; 
}; 

Trong các phiên bản cũ của C++ bạn cần phải tự viết một constructor mặc định khởi tạo tất cả các thành viên (cú pháp mới trên là chỉ đường cho việc này):

struct foo 
{ 
    foo() : my_bool(), my_int() { } 
    bool my_bool; 
    int my_int; 
}; 

như ghi chú @sbi, nếu bạn muốn tự khởi tạo các cấu trúc, thậm chí không có constructor mặc định, bạn có thể làm foo myFoo = foo();

+1

+1.Ngoài việc trong phong cách của C, tôi đã đi xa như vậy để nói rằng đó là một phong cách xấu ngay cả trong C (phổ biến như nó được). Peter van der Linden đi sâu về điều này trong cuốn sách cá xấu xí, nhưng viết * struct foo * không khó để viết và cung cấp một tên nhất quán cho loại dễ khai báo hơn (thay vì cái gì đó như * struct st_foo * và a * foo * typedef cho nó). – stinky472

1

chừng nào bạn đang khai báo struct trong một C-way, bạn có thể sử dụng zeromemory để không chính xác sizeof(foo) byte, do đó, mặc định tất cả các giá trị thành 0.

Trong C++, bạn có thể xác định cấu trúc của bạn bằng một hàm tạo sẽ đặt giá trị của bạn thành một số giá trị mặc định nếu cần.

+2

Và nếu sau đó ai đó thêm 'double my_fpn;', thì điều này có thể thất bại khi thực hiện một 'double' với tất cả các bit được đặt bằng 0 không phải là số dấu phẩy động hợp lệ. – sbi

1

c và C++ không khởi tạo biến. Chúng chứa bất cứ điều gì xảy ra ở trong vị trí bộ nhớ mà chúng đang ở trước đây. Điều này cũng áp dụng cho các biến thành viên trong các lớp và các cấu trúc trừ khi bạn khởi tạo chúng một cách cụ thể thành một giá trị.

+0

Điều này không đúng đối với C++. Một 'std :: string s;' chắc chắn sẽ khởi tạo 's'. – sbi

+0

std :: string tạo một đối tượng và gọi hàm tạo của nó và khởi tạo nó một cách rõ ràng. Đó có thể là sự khác biệt về mặt kỹ thuật, nhưng tuyên bố của tôi vẫn chính xác. Trong trường hợp này, ông có thể tạo ra một constrictor cho cấu trúc của mình và có được hành vi tương tự. Điều đó có nghĩa là nó đang được tự động khởi tạo? Không thật sự lắm. – Donnie

+0

bạn không phải khởi tạo nó thành giá trị, v.d. 'int i = int();' gọi hàm dựng mặc định "của int, và do đó khởi tạo i với giá trị mặc định là 0 – smerlin

4

Có một constructor mặc định:

struct foo { 
    foo() : my_bool(false), my_int(0) {} 
    bool my_bool; 
    int my_int; 
}; 
10

Thực hiện một constructor mặc định:

typedef struct foo 
{ 
    foo() 
    : my_bool(false), my_int(0) 
    { 
     // Do nothing 
    } 
    bool my_bool; 
    int my_int; 
} foo; 
+2

Tôi nghĩ rằng điều này tốt hơn nhiều tùy thuộc vào việc khởi tạo ngầm của các thành viên dữ liệu. Đặc biệt nhất là nếu bạn tình cờ viết mã trung lập nền tảng. Ngay cả khi bạn mong đợi tất cả các trình biên dịch để hoạt động giống hệt nhau, vẫn còn tốt để được rõ ràng về ý định của bạn. Nó hỗ trợ khả năng đọc, bảo trì và giúp những người đến sau bạn. –

2

Bạn chưa tạo bất kỳ đối tượng trong mã đó. Khởi tạo được thực hiện khi bạn tạo các đối tượng, và không được đặc biệt giấu theo cách bạn khai báo cấu trúc.

Ví dụ sau đây khởi boolean để false và số nguyên để 0

foo f = { }; 

Chú ý rằng bạn chỉ có typdefed struct của bạn. Bạn chưa tạo một đối tượng. Giống như những người khác nói rằng bạn có thể bỏ qua typedef trong C++ và chỉ cần khai báo cấu trúc, và bạn vẫn có thể tham khảo kiểu bằng cách chỉ nói foo.

Nếu bạn bỏ qua khởi tạo rõ ràng khi bạn xác định đối tượng, thì chắc chắn không khởi tạo được trừ khi đối tượng được xác định tại phạm vi không gian tên hoặc được xác định là static cục bộ (trong trường hợp tất cả thành viên không được khởi tạo) hoặc lớp một hàm tạo mặc định do người dùng định nghĩa để khởi tạo tương ứng.

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