2014-09-12 16 views
5

Tôi có cấu trúc c mà tôi muốn nhúng vào một lớp cpp mà không bị nhiễm độc vùng tên chung của tôi vì vậy tôi không muốn bao gồm tiêu đề c.QScopedPointer, boost :: scoped_ptr - tại sao phàn nàn về các loại không đầy đủ?

Đó là lý do tại sao tôi muốn sử dụng con trỏ có phạm vi thông minh (QScopedPointer hoặc boost::scoped_ptr) với tên cấu trúc được khai báo chuyển tiếp.

Những gì tôi không hiểu là việc thực hiện của cả hai đề cập con trỏ chỉnh phạm vi mà không thành công trên biên dịch:

tăng:

lỗi C2027: sử dụng các loại không xác định 'xxx'

template<class T> inline void checked_delete(T * x) 
{ 
    // intentionally complex - simplification causes regressions 
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here 
    (void) sizeof(type_must_be_complete); 
    delete x; 
} 

và giống nhau trong Qt:

lỗi C2027: sử dụng các loại không xác định 'xxx'

template <typename T> 
struct QScopedPointerDeleter 
{ 
    static inline void cleanup(T *pointer) 
    { 
     // Enforce a complete type. 
     // If you get a compile error here, read the section on forward declared 
     // classes in the QScopedPointer documentation. 
     typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; // < here 
     (void) sizeof(IsIncompleteType); 

     delete pointer; 
    } 
}; 

Các tài liệu tham khảo không giúp tôi. nó nói rằng destructor của lớp được khai báo phía trước không phải là inline và phải có sẵn ở mọi khả năng instantiation của cleanup của scoped pointer. Nhưng c-cấu trúc của tôi không có một destructor.

Vì vậy, tôi có 2 câu hỏi:

  1. Tại sao việc kiểm tra này ở tất cả? Bởi vì có vẻ như không liên quan đến việc biết kích thước để gọi xóa.
  2. Làm cách nào để giải quyết vấn đề này?

Trả lời

8
  1. Các loại đối tượng được lưu giữ trong con trỏ thông minh phải được biết ở nơi con trỏ thông minh đang được destructed, destructor rất thích hợp của đối tượng giữ có thể được gọi
  2. làm lớp học của bạn (một trong đó chứa thông minh con trỏ) có destructor? Nếu không - thêm một trong tệp cpp của bạn. Nếu không, trình biên dịch sẽ cố gắng thêm một khi nó thấy định nghĩa lớp của bạn và không thể làm điều đó vì destructor của con trỏ thông minh cố gắng truy cập loại không xác định.
+0

ah tôi đã bỏ qua dòng nhỏ với định nghĩa phá hủy ảo trống trong phần khai báo lớp. sau khi chuyển nó sang cpp, lỗi đã biến mất. –

6

Cấu trúc c của tôi không có hàm hủy.

Có một điều, Không. Cấu trúc của bạn thực sự có trình phá hủy - implicitly-declared destructor.


Dù sao, hãy tiếp tục.

delete pointer; 

Khi biên dịch mã này, chúng ta nên gọi hàm hủy là *pointer. Tuy nhiên, nếu *pointer là loại không đầy đủ, chúng tôi không thể biết destructor để gọi. Trong trường hợp này, tiêu chuẩn [expr.delete] cho biết nó gây ra hành vi không xác định.

Nếu đối tượng bị xóa có kiểu lớp đầy đủ tại thời điểm xóa và đầy đủ các lớp có một destructor không tầm thường hoặc một chức năng deallocation, hành vi này là không xác định.

Như bạn có thể thấy, nếu cấu trúc của bạn không có hàm hủy không tầm thường hoặc hàm deallocation (lớp cụ thể operator delete), nó không phải UB. Tuy nhiên, bạn có thể thêm một destructor vào cấu trúc của bạn - bạn sẽ làm. Nếu bạn không sửa lỗi này, nó sẽ trở thành lỗi thực sự. (Trình biên dịch không phải báo cáo nó, nó chỉ là UB, không phải mã bất hợp pháp.) Vì vậy, nó là không được coi là một thực hành tốt.

Do đó, việc xóa các loại không hoàn chỉnh thực sự là những gì chúng ta nên tránh. Để tránh điều đó, chúng tôi sử dụng thủ thuật này.

typedef char type_must_be_complete[ sizeof(T)? 1: -1 ]; // < here 
(void) sizeof(type_must_be_complete); 

Kể từ sizeof(T) là mã bất hợp pháp nếu T là loại không đầy đủ, vì vậy nó có thể làm giảm lỗi thời gian biên dịch trước khi chương trình của bạn đi là điên do UB.

Tôi đặc biệt khuyên bạn nên chỉ bao gồm nó mặc dù tốc độ tuân thủ chậm hơn; Mặc dù cấu trúc của bạn là tầm thường và không có operator delete, chúng có thể được thêm mà không cần sửa chữa, điều này gây ra UB.

+0

cấu trúc xuất phát từ một đầu ra 'extern 'C' {}' và thực hiện từ một thư viện C thuần túy được liên kết riêng biệt. làm thế nào có thể có một destructor. nhưng tôi đồng ý rằng tất nhiên cho các lớp học thường xuyên nội dung của họ phải được biết để quyết định nếu có một số destructor hoặc nếu trực tiếp giải phóng bộ nhớ. –

+0

@vlad_tepesch là thư viện thư viện bên thứ ba bên ngoài (ví dụ: libgmp) hoặc thư viện của riêng bạn hiện đang được viết? – ikh

+0

lib nằm trong tay của tôi nhưng nó chỉ là giả thiết để cho thấy rằng nó có thể thực sự không có destructor và không có khả năng để tạo ra một ngầm (ví dụ, nếu thư viện tự ẩn định nghĩa cấu trúc và cung cấp một chức năng nhà máy). như nhận xét của tôi về câu trả lời khác nói - tôi có thể tìm và loại bỏ vấn đề. –

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