2011-08-22 40 views
13

Một cách hay trong C++ để phát hiện trong một destructor là nó đang được chạy trong khi thư giãn của ngăn xếp do một ngoại lệ được ném như trái ngược với một lối ra bình thường của phạm vi kích hoạt các destructor? Tôi muốn biết để tôi có thể tạo một lớp có một số mã dọn dẹp luôn luôn chạy trên lối ra bình thường nhưng bỏ qua khi một ngoại lệ xảy ra.Phát hiện khi destructor chạy do ngoại lệ bị ném?

+0

Câu hỏi thú vị! Tôi bị cám dỗ để nói rằng nó không thể được thực hiện, bởi vì các đối tượng không thực sự biết rằng một ngoại lệ là hoạt động, họ chỉ đi ra khỏi phạm vi như là ngoại lệ thư giãn ngăn xếp, giống như nếu họ đi ra khỏi bất kỳ khác phạm vi. Nếu bất cứ điều gì bạn cần một số "hack" nền tảng cụ thể ... –

+1

Tò mò lý do tại sao bạn muốn tránh dọn dẹp trong khi mở thư? –

+0

@Eric Z: Tôi đã nghĩ đến việc sử dụng tính năng này để ghi nhật ký 'stack' tự động. Một cái gì đó dọc theo dòng của 'Đăng nhập xxx ("funcA -", arg1, arg2, arg3); ', nhưng dụng cụ chức năng là tẻ nhạt. –

Trả lời

16

std::uncaught_exception() (quy định tại <exception>) sẽ cho bạn biết trong destructor của bạn nếu nó được gọi vì một ngoại lệ:

class A 
{ 
public: 
    ~A() 
    { 
     if (std::uncaught_exception()) { 
      // Called because of an exception 
     } else { 
      // No exception 
     } 
    } 
}; 
+0

Tốt, tôi chưa bao giờ biết điều này đã tồn tại! :-) –

+0

Không đẹp như bạn nghĩ - hãy xem bài viết được liên kết trên bài đăng của tôi. – Simon

0

Dưới đây là một cách tôi có thể nghĩ ra, nhưng có vẻ như vụng về:

{ 
    myCleanupClass unwindAction; 
    try { 
    // do some work which may throw exception. 
    } catch (...) { 
    unwindAction.disableDestructorWork(); 
    throw; 
    } 
} 
1

Đừng làm điều đó trừ khi bạn có lý do chính đáng. Ngăn xếp thư giãn là một tính năng ngôn ngữ mà tất cả các đối tượng tự động bên trong khối try sẽ được thực thi để deallocate, để các nguồn lực bên trong chúng có cơ hội để phát hành.

Bạn muốn bỏ qua dọn dẹp trong dtor trong khi thư giãn thư giãn, bỏ qua mục đích ban đầu của nó. Và bạn sẽ có nguy cơ bị rò rỉ tài nguyên.

Ví dụ

class CDBConnection 
{ 
    public: 
    CDBConnection() 
    { 
     m_db.open(); 
    } 
    ~CDBConnection() 
    { 
     if (!std::uncaught_exception()) 
     m_db.close(); 

     // if this is called during a stack unwinding, 
     // your DB connection will not be closed for sure. 
     // That's a resource leakage. 
    } 
    //.. 
    private: 
    DB m_db; 
}; 

void main() 
{ 
    //.. 
    try 
    { 
    // code that may throw 
    CDBConnection db; 
    //..   
    } 
    catch(const CDBException& exp) 
    { 
    // properly handle the exception 
    } 
} 
4

lẽ this bài viết sẽ giúp bạn. Bài viết sẽ cho bạn thấy các vấn đề với std :: uncaught_exception() và chứa một lời khuyên làm thế nào để đối phó với các ngoại lệ trong các destructors.

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