2012-04-04 30 views
9

Hãy xem xét điều này:Rõ ràng khởi tạo vector của con trỏ dẫn đến lỗi chuyển đổi?

std::vector<int*> v(1, 0); 

này biên dịch tốt với VC++ 10 (không có cảnh báo ngay cả ở mức báo động tối đa). Tuy nhiên, nó không biên dịch với llvm trên mac hoặc gcc trên linux, đưa ra một lỗi như "gán cho int * từ int không tương thích kiểu int." Tôi không tìm kiếm giải pháp - Tôi biết tham số thứ hai là không cần thiết hoặc một static_cast sửa lỗi.

Tôi nghĩ số không được chuyển đổi hoàn toàn thành bất kỳ loại con trỏ nào. Đưa cái gì? Tôi có thể làm như sau:

int* i = 0; 
int* const& ii = 0; 
const int t = 0; 
i = t; 

Tôi hiểu rằng chữ ký constructor vector mất một const T& mà khi mở rộng cho vector<int*> trở thành int* const& có đúng không? Ai đó có thể giải thích những gì đang xảy ra ở đây, và cho dù trình biên dịch VC++ hoặc phi VC++ là chính xác?

+0

Thử 'nullptr' thay vì' 0'. – ildjarn

+1

Bạn có biên dịch chương trình này dưới dạng chương trình C++ 03 hoặc C++ 11 không? –

+0

Không liên quan đến câu hỏi, nhưng, tại sao bạn lại sử dụng các con trỏ thô khi [Bjarne nói chúng ta nên tránh chúng] (http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11- Phong cách)? –

Trả lời

2

Dường như g ++ thực sự sai ở đây. Xem C++ 98 23.1.1/9:

Đối với mỗi chuỗi quy định tại khoản này và tại khoản 21:

- các constructor mẫu X (InputIterator f, InputIterator l, const cấp phát & a = Allocator())

sẽ có cùng hiệu lực là: X(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l), a) nếu InputIterator là loại tích phân .

Lưu ý rằng InputIterator là tham số mẫu cho hàm tạo, trong trường hợp này là int cho ví dụ của bạn và do đó là một loại tích phân. Thư viện g ++ thực sự có mã cụ thể để xử lý tất cả các trường hợp mà kiểu được lưu trữ trong vector cũng không thể thiếu và tất cả các mã đó đều hoạt động bình thường. Trong trường hợp này, chỉ vì bạn đã sử dụng 0, số static_cast được quyết định bởi tiêu chuẩn thực sự là hợp pháp. Tôi đã thử biên dịch mã mà tiêu chuẩn nói phải tương đương và nó biên dịch với g ++ 4.5.

+0

công việc tốt. 'std :: vector v (1, 0);' biên dịch tốt. tôi đã không mong đợi MS được chính xác ở đây. – Tabber33

+0

Điều đó tùy thuộc vào việc triển khai đã xem xét [Vấn đề thư viện # 438] hay không (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#438) cho biết rằng điều này không có nghĩa là t làm việc. Giải pháp được đề xuất là 'X (static_cast (f), l, a)' khớp với lỗi của Tabber. Thay vào đó, C++ 11 đã theo sau [Báo cáo lỗi số 1234] (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#1234) với một kết quả khác. –

2

std::vector có một constructor khó chịu với chữ ký này

template <class InputIterator> 
vector(InputIterator first, InputIterator last, 
     const Allocator& = Allocator()); 

đó, nếu trình biên dịch khấu trừ InputIterator như int (!) Từ thông số của bạn 01, sẽ là một sự phù hợp tốt nhưng không làm những gì chúng ta muốn.

Tôi tin rằng C++ 11 yêu cầu trình biên dịch thử khó hơn để tìm hiểu xem các tham số có thực sự là trình lặp hay không. Trong C++ 03, chúng có thể sẽ kết thúc là size_type(1)int(0), gây ra sự cố của bạn.

Số nguyên chữ 0 có thể chuyển đổi thành con trỏ rỗng, nhưng int có giá trị 0 thì không!

+0

cảm ơn bạn. bạn là chính xác - nhìn vào các lỗi chặt chẽ hơn, bây giờ tôi thấy rằng instantiation của constructor templated là ở gốc của cây lỗi. tôi chỉ tự hỏi tại sao VC++ (ngay cả hỗ trợ pre-C++ 11) đi đến "rắc rối" bổ sung để gọi các nhà xây dựng dự định ở đây, và vi phạm các quy tắc ngôn ngữ để làm như vậy (sau khi tất cả, constructor templatized là một trận đấu tốt hơn)? – Tabber33

+0

@Bo Persson Nếu tôi đọc 23.1.1/9 đúng, đây không phải là câu trả lời đúng: g ++ thực sự bỏ lỡ một trường hợp đặc biệt. –

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