2010-10-26 35 views
5

Dưới đây là hai đoạn (sẵn sàng biên dịch) mã. Trong đoạn đầu tiên, trong đó tôi chỉ sử dụng khai báo chuyển tiếp cho một cấu trúc trong khi xóa con trỏ đến cấu trúc này từ một trình băm lớp cơ sở cho một lớp Khách không được gọi.
Trong đoạn thứ hai khi thay vì khai báo về phía trước, tôi sử dụng định nghĩa đầy đủ của lớp Khách này bằng cách sử dụng xóa trong cơ sở hoạt động ase dự định.
Tại sao? Tại sao nó tạo nên sự khác biệt? Không phải là tuyên bố về phía trước giả sử là chỉ là một lưu ý cho một trình biên dịch nói rằng định nghĩa của lớp này/struct là ở một nơi khác?
Tôi rất ngạc nhiên vì nó không hoạt động một cách trực giác.Tuyên bố chuyển tiếp sẽ không thực hiện

//First just forward dclr 
#include "stdafx.h" 
#include <iostream> 
using std::cout; 

struct Guest; 

struct Base 
{ 
    Guest* ptr_; 
    Base(Guest* ptr):ptr_(ptr) 
    { 
     cout << "Base\n"; 
    } 
    ~Base() 
    { 
     cout << "~Base\n"; 
     delete ptr_; 
    } 
}; 

struct Guest 
{ 
    Guest() 
    { 
     cout << "Guest\n"; 
     throw std::exception(); 
    } 
    Guest(int) 
    { 
     cout << "Guest(int)\n"; 
    } 
    ~Guest() 
    { 
     cout << "~Guest\n"; 
    } 
}; 

struct MyClass : Base 
{ 
    Guest g; 
    MyClass(Guest* g):Base(g) 
    { 
     cout << "MyClass\n"; 

    } 
    ~MyClass() 
    { 
     cout << "~MyClass\n"; 
    } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    try 
    { 
     Guest* g = new Guest(1); 
    MyClass mc(g); 
    } 
    catch(const std::exception& e) 
    { 
     std::cerr << e.what(); 
    } 
    return 0; 
} 

// Thứ hai - đầy đủ def

#include "stdafx.h" 
#include <iostream> 
using std::cout; 

struct Guest 
{ 
    Guest() 
    { 
     cout << "Guest\n"; 
     throw std::exception(); 
    } 
    Guest(int) 
    { 
     cout << "Guest(int)\n"; 
    } 
    ~Guest() 
    { 
     cout << "~Guest\n"; 
    } 
}; 

struct Base 
{ 
    Guest* ptr_; 
    Base(Guest* ptr):ptr_(ptr) 
    { 
     cout << "Base\n"; 
    } 
    ~Base() 
    { 
     cout << "~Base\n"; 
     delete ptr_; 
    } 
}; 



struct MyClass : Base 
{ 
    Guest g; 
    MyClass(Guest* g):Base(g) 
    { 
     cout << "MyClass\n"; 

    } 
    ~MyClass() 
    { 
     cout << "~MyClass\n"; 
    } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    try 
    { 
     Guest* g = new Guest(1); 
    MyClass mc(g); 
    } 
    catch(const std::exception& e) 
    { 
     std::cerr << e.what(); 
    } 
    return 0; 
} 
+0

Bạn nên tạo các trình tạo lớp cơ sở ảo trong cả hai trường hợp. –

+0

@ Space_C0wb0y: Kính gửi, bạn không thể tạo một hàm tạo ảo trong C++ :) –

+0

@Armen: Từ ngữ ... khói và gương. Nó rất rõ ràng trong đầu tôi. (Đối với những người tự hỏi, nó sẽ là * destructors *) –

Trả lời

3

Không chính thức: trình biên dịch cần định nghĩa lớp để xóa đối tượng chính xác, vì nó cần biết cách gọi hàm hủy và/hoặc operator delete cho lớp đó.

Chính thức, 5.3.5/5:

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

Bạn sẽ được OK nếu (ví dụ) Guest là POD, nhưng bạn đã cho nó một trình phá hủy, vì vậy bạn không OK.

3

Bạn không thể xóa Guest trừ khi bạn biết định nghĩa của nó. Đó là destructor sẽ không được gọi. Ngoài ra, nếu Khách đã xác định xóa nhà điều hành tùy chỉnh, nó sẽ bị bỏ qua.

+0

declaration -> definition :) –

+0

Không, khai báo là đủ. Tuy nhiên, một tuyên bố về phía trước sẽ không làm. –

+0

@kotlinski - 'class X {void f(); }; 'đây là định nghĩa của X trong khi' lớp X; 'là khai báo –

16

Từ C++ chuẩn (5.3.5/5):

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

Vì vậy, bạn không thể sử dụng xóa trên loại không hoàn chỉnh của mình. Nó sẽ gọi destructor và trình biên dịch vẫn chưa nhận thức được nó.

3

Bạn không thể xóa con trỏ thành loại không hoàn chỉnh. Xóa là một trong các thao tác yêu cầu loại cần hoàn thành. HTH

2

Loại ptr_ không đầy đủ khi bạn gọi delete trên đó. Điều này dẫn đến hành vi không xác định. Vì vậy, destructor của bạn có thể không được gọi. Bạn có thể sử dụng Boost.checked_delete để tránh các tình huống như vậy.

2

(. Phần header stdafx.h không phải là tiêu chuẩn C++) Nếu tôi biên dịch với g ++, trình biên dịch tạo ra:

warning: possible problem detected in invocation of delete operator: 
warning: invalid use of incomplete type ‘struct Guest’ 
warning: forward declaration of ‘struct Guest’ 
note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined. 

Cấu hình trình biên dịch của bạn để biên dịch ở mức cảnh báo và lỗi thích hợp.

+1

int _tmain (int argc, _TCHAR * argv []) <- đây cũng không phải là tiêu chuẩn –

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