2011-04-04 25 views
7

Hãy nói rằng tôi có các loại sau:Làm thế nào để làm một khẳng định tĩnh rằng một con trỏ cast là tầm thường?

struct A { 
    int a; 
}; 

struct B { 
    int b; 
}; 

struct C : public A, public B { 
    int c; 
}; 

Một con trỏ C* có thể được đúc để A* con trỏ mà không điều chỉnh địa chỉ thực tế chút nào. Nhưng khi C* được truyền tới B*, giá trị phải thay đổi. Tôi muốn đảm bảo rằng hai loại liên quan tôi có thể được đúc với nhau mà không thay đổi địa chỉ (nghĩa là không có nhiều thừa kế, hoặc lớp cơ sở là cơ sở đầu tiên của lớp dẫn xuất). Điều này có thể được kiểm tra tại thời gian chạy, ví dụ: giống như vậy

assert(size_t(static_cast<A*>((C*)0xF000) == 0xF000); 
assert(size_t(static_cast<B*>((C*)0xF000) != 0xF000); 

Điều đó có hiệu quả. Nhưng thông tin này được biết ở thời gian biên dịch, vì vậy tôi đang tìm cách để thực hiện một xác nhận biên dịch trên đó. Các cách rõ ràng để chuyển đổi ở trên thành một khẳng định tĩnh (ví dụ: thay thế assert bằng lỗi BOOST_STATIC_ASSERT cho lỗi "một loại bỏ với loại không phải là loại tích phân hoặc kiểu liệt kê không thể xuất hiện trong biểu thức không đổi" với g ++ 4.2.

Tính di động không phải là quá quan trọng Sử dụng tiện ích gcc, hoặc mẫu thủ đoạn hacky tất cả sẽ ổn thôi

cập nhật:.. Tìm thấy rằng gần như cùng một câu hỏi đã được hỏi trước:. C++, statically detect base classes with differing addresses? Sử dụng offsetof() chỉ là gợi ý hữu ích ở đó quá.

+8

Không muốn trở thành một nitpick, nhưng vì bố cục bộ nhớ chính xác là chi tiết triển khai ... tại sao bạn lại quan tâm đến điều này một cách chính xác? –

+0

Tôi khá chắc chắn rằng thư viện Boost/lambda chứa nội dung cho việc này. Tôi phải xem xét nó nhưng Alexandrescu và Vandervoorde đã xuất bản chỉ là về mọi thủ thuật trong lĩnh vực này – sehe

+0

Tôi thực sự quan tâm đến câu hỏi mà @Matthieu M. trình bày: Dưới những trường hợp nào có vấn đề nếu một diễn viên có thể tầm thường? (tức là nếu nó không nhỏ, chi phí có thể không đáng kể: thêm một hằng số vào con trỏ có nguồn gốc, và nếu điều kiện không được thực hiện đúng cách, bạn sẽ chạy vào cơn đau thực sự cố gắng gỡ lỗi bộ nhớ sẽ bị hỏng) –

Trả lời

1

Dựa trên đề xuất từ ​​MSalters và câu trả lời từ C++, statically detect base classes with differing addresses?, đây là điều gần nhất với câu trả lời tôi có thể đưa ra. Đây có thể là gcc-cụ thể, và đòi hỏi phải biết một số thành viên của lớp cơ sở:

#pragma GCC diagnostic ignored "-Winvalid-offsetof"  // To suppress warning. 
BOOST_STATIC_ASSERT(offsetof(C, a) == offsetof(A, a)); 
BOOST_STATIC_ASSERT(offsetof(C, b) != offsetof(B, b)); 
#pragma GCC diagnostic warn "-Winvalid-offsetof" 

Rõ ràng đây là cả hai bất tiện và đáng sợ (yêu cầu phải biết một thành viên và để tắt một cảnh báo).

4

"Tôi muốn đảm bảo rằng hai liên quan các loại có thể được truyền tới nhau mà không thay đổi địa chỉ (tức là rằng không có nhiều thừa kế hoặc lớp cơ sở là cơ sở đầu tiên của lớp dẫn xuất). "

" nghĩa là "của bạn không đúng. Ví dụ, hoàn toàn có thể là 4 byte đầu tiên của Derived là Có, trình biên dịch C++ dễ dàng hơn nếu (1) subobject cơ bản đầu tiên là ở offset 0, và (2) con trỏ vtable được bù trừ 0. Nhưng hai mục tiêu đó vốn có tại tỷ lệ cược, và không có sự lựa chọn rõ ràng tốt hơn,

Bây giờ, phần đầu tiên có thể được kiểm tra theo lý thuyết. cho các loại thú vị; s UB. Và toàn bộ điểm của kiểm tra này là để kiểm tra một loại, do đó, nó sẽ không đáng tin cậy cho các loại bố cục không chuẩn.

+1

"Bạn không thể kiểm tra điều đó, bởi vì nó không đúng". Ý tôi là vì nó không phải lúc nào cũng đúng, tôi cần kiểm tra! Bây giờ, ý tưởng offsetof (C, a) có vẻ rất hứa hẹn, nhưng gcc than phiền về "Truy cập không hợp lệ vào thành viên dữ liệu không tĩnh 'A :: a' của đối tượng NULL." –

+0

Thực ra, khiếu nại gcc là cảnh báo chứ không phải lỗi. Vì vậy, điều này không hoạt động khi thành viên đầu tiên của Base được biết đến. Đó là một cái gì đó. Cảm ơn! –

+0

Tôi đã chỉnh sửa bình luận của MSalters "Bạn không thể kiểm tra điều đó, bởi vì nó không đúng" với tôi nghĩ "rõ ràng hơn" của bạn "tức là ' không đúng ". Tôi không nghĩ rằng MSalters có thể đã cố gắng để nói rằng toàn bộ tuyên bố của bạn là sai. Dựa trên câu tiếp theo của mình, tôi nghĩ anh ta chỉ có nghĩa là "hai loại liên quan có thể được đúc ..." không thực sự thực sự tương đương với "không có nhiều thừa kế ...". – Quuxplusone

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