2009-12-08 33 views
12

Có quy tắc hay không để quyết định thời điểm sử dụng cú pháp cũ () thay vì cú pháp mới {}?Khởi tạo đồng bộ trong C++ 0x, khi nào nên sử dụng() thay vì {}?

Để khởi tạo một cấu trúc:

struct myclass 
{ 
    myclass(int px, int py) : x(px), y(py) {} 
private: 
    int x, y; 
}; 
... 
myclass object{0, 0}; 

Bây giờ trong trường hợp của một vector ví dụ, nó có nhiều nhà xây dựng. Bất cứ khi nào tôi làm như sau:

vector<double> numbers{10}; 

tôi nhận được một vector của yếu tố thay vì một với yếu tố là một trong những nhà xây dựng là:

explicit vector (size_type n, const T& value= T(), const Allocator& = Allocator()); 

nghi ngờ của tôi là bất cứ khi nào một lớp định nghĩa một constructor initializer list như trong trường hợp của một vector, nó được gọi với cú pháp {}.

Vì vậy, đó là những gì tôi đang suy nghĩ chính xác. tức là Tôi có nên hoàn nguyên về cú pháp cũ chỉ khi nào một lớp định nghĩa một hàm tạo danh sách khởi tạo để gọi một hàm tạo khác không? ví dụ: để sửa đoạn code trên:

vector<double> numbers(10); // 10 elements instead of just one element with value=10 
+6

Điều đó có nghĩa là người dùng có thể phá vỡ một lớp khách hàng khi thêm các nhà xây dựng danh sách khởi tạo không? Ouch. –

+2

Không, hàm tạo khởi tạo không ảnh hưởng đến các hàm tạo khác tại chỗ AFAIK. –

+1

@dribeas: Điều đó có chắc chắn không. Giả sử lớp của bạn ban đầu có một hàm tạo lấy một đối số int duy nhất và bạn vui vẻ tạo các cá thể bằng cú pháp mới. Nếu một hàm tạo mới được thêm vào có 'initializer_list ', thì không phải tất cả các đối tượng này hiện đang sử dụng hàm tạo bổ sung chưa? Trừ khi các ví dụ trên mạng đã lỗi thời và tuyên bố một vectơ có danh sách nên thực tế trông giống như 'vector v {{2, 1}}; 'Tôi không thấy các dấu ngoặc ở bất kỳ đâu. – UncleBens

Trả lời

2

Hãy xem này:

http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=453&rll=1

Việc sử dụng một {} initializers kiểu trên một biến không có ánh xạ trực tiếp vào danh sách khởi tạo trên bất kỳ nhà thầu của lớp. Các danh sách khởi tạo của hàm khởi tạo đó có thể được thêm/xóa/sửa đổi mà không phá vỡ người gọi hiện tại.

Về cơ bản, hành vi khác nhau của vùng chứa là đặc biệt và yêu cầu mã đặc biệt trong vùng chứa đó, cụ thể là một hàm tạo dùng std::initializer_list. Đối với POD và các đối tượng đơn giản, bạn có thể sử dụng {}() thay thế cho nhau.

+0

"Đối với POD và các đối tượng đơn giản, bạn có thể sử dụng {} và() thay thế cho nhau." Không, '()' chỉ hoạt động nếu có một hàm khởi tạo, mà (ngoài việc tạo ra bản sao) loại bỏ đối tượng khỏi bị POD. '{}' mặt khác vẫn hoạt động. – Potatoswatter

9

tôi đã tìm thấy câu trả lời trong các tài liệu tiêu chuẩn (latest draft). Hy vọng rằng, tôi sẽ cố gắng giải thích những gì tôi đã hiểu.

Đầu tiên, nếu một lớp định nghĩa một constructor danh sách khởi tạo, sau đó nó được sử dụng bất cứ khi nào thích hợp:

§ 8.5.4 (trang 203)

Initializer-list nhà xây dựng đang ưa chuộng hơn các nhà thầu khác trong số khởi tạo danh sách (13.3.1.7).

Tôi nghĩ rằng đây là một tính năng tuyệt vời để có, loại bỏ sự đau đầu liên quan đến việc không đồng nhất phong cách :)

Dù sao, Gotcha chỉ (mà câu hỏi của tôi là về) là nếu bạn thiết kế một lớp không có hàm tạo khởi tạo, sau đó bạn thêm nó sau này, bạn có thể nhận được kết quả đáng ngạc nhiên.

Về cơ bản, hãy tưởng tượng std::vector không có nhà xây dựng danh sách initializer, sau đó những điều sau đây sẽ tạo ra một vector với 10 yếu tố:

std::vector<int> numbers{10}; 

Bằng cách thêm các nhà xây dựng danh sách initializer, trình biên dịch sẽ ủng hộ nó trong khác hàm tạo bởi vì cú pháp {}. Hành vi này sẽ xảy ra vì các phần tử của danh sách init {10}được chấp nhận bằng cách sử dụng hàm tạo danh sách init. Nếu không có chuyển đổi được chấp nhận, bất kỳ hàm tạo khác nào cũng sẽ được sử dụng, ví dụ:

std::vector<string> vec{10}; 
// a vector of 10 elements. 
// the usual constructor got used because "{0}" 
// is not accepted as an init-list of type string. 
Các vấn đề liên quan