2011-12-23 24 views
5
// main_pimpl_sample.cpp 
#include "pimpl_sample.hpp" 

using namespace std; 

int main() 
{ 
    pimpl_sample p; 

    return 0; 
} 

// pimpl_sample.cpp 

#include "pimpl_sample.hpp" 

struct pimpl_sample::impl { 
}; 

pimpl_sample::pimpl_sample() 
    : pimpl_(new impl) { 
} 

// pimpl_sample::~pimpl_sample() 
// cause problem if missed 
// {} 


// pimpl_sample.hpp 

#if !defined (PIMPL_SAMPLE) 
#define PIMPL_SAMPLE 

#include <boost/scoped_ptr.hpp> 

class pimpl_sample { 
    struct impl; 
    boost::scoped_ptr<impl> pimpl_; 

public: 
    pimpl_sample(); 
    //~pimpl_sample(); cause problem if missed 
    void do_something(); 
}; 

#endif 


~/Documents/C++/boost $ g++ --version 
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2 

~/Documents/C++/boost $ g++ -o main_pimpl_sample main_pimpl_sample.cpp pimpl_sample.cpp pimpl_sample.hpp 
In file included from /usr/include/boost/smart_ptr/scoped_ptr.hpp:15:0, 
       from /usr/include/boost/scoped_ptr.hpp:14, 
       from pimpl_sample.hpp:6, 
       from main_pimpl_sample.cpp:2: 
/usr/include/boost/checked_delete.hpp: In function ‘void boost::checked_delete(T*) [with T = pimpl_sample::impl]’: 
/usr/include/boost/smart_ptr/scoped_ptr.hpp:80:9: instantiated from ‘boost::scoped_ptr<T>::~scoped_ptr() [with T = pimpl_sample::impl]’ 
pimpl_sample.hpp:8:20: instantiated from here 
/usr/include/boost/checked_delete.hpp:32:58: error: invalid application of ‘sizeof’ to incomplete type ‘pimpl_sample::impl’ 
/usr/include/boost/checked_delete.hpp:32:58: error: creating array with negative size (‘-0x00000000000000001’) 

Giải pháp cho lỗi biên dịch ở trên là tự cung cấp hàm hủy. Lý do được chỉ định như sau:Phải cung cấp hàm hủy trong PIMPL

bạn vẫn phải nhớ xác định trình phá hủy theo cách thủ công; lý do là tại thời điểm trình biên dịch tạo ra một destructor ngầm, các loại impl là không đầy đủ, do đó, destructor của nó không được gọi.

Câu hỏi> tôi vẫn còn có những khó khăn để hấp thụ các ý tưởng trên và muốn biết một chi tiết chút lý do tại sao chúng tôi phải cung cấp một destructor thủ công ở đây.

Cảm ơn bạn

Trả lời

7

TL; DR Khai báo một destructor rõ ràng và thực hiện nó trong một mô-đun mã (không trong file header).

Nếu bạn không tạo trình phá hủy, trình biên dịch sẽ tạo một hủy tự động trống trong mọi đơn vị dịch để cố gắng phá hủy đối tượng của lớp này. Bạn sẽ nhận được hành vi tương đương nếu bạn định nghĩa một destructor nội tuyến rỗng trong tiêu đề lớp.

Điều này gây ra lỗi vì hàm hủy cũng chịu trách nhiệm gọi các trình phá hủy của tất cả các trường của lớp, theo thứ tự - cần sự khởi tạo của mẫu phương thức boost::scoped_ptr<impl>::~scoped_ptr();. Bản mẫu này, đến lượt nó, có thể không được khởi tạo sau đó vì nó cố gắng xóa một đối tượng kiểu impl, mà chỉ về phía trước khai báo trong phạm vi đó (và bạn cần một định nghĩa đầy đủ để biết làm thế nào để xóa đối tượng này.


OTOH, nếu bạn khai báo các nhà xây dựng không inline trong tiêu đề, mã của nó chỉ được tạo ra trong pimpl_sample.cpp, nơi cũng nằm trong định nghĩa của impl, vì vậy destructor của scoped_ptr có thể được khởi tạo thành công.

đơn vị dịch khác thì chỉ gọi pimpl_sample 's destructor như một phương pháp bên ngoài, vì vậy họ không cần phải tạo ra nó và nhanh chóng scoped_ptr phá hủy của riêng họ.

+0

Tôi đã thêm bản tóm tắt ngắn gọn, vui lòng chỉnh sửa/hoàn nguyên. – krlmlr

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