2008-10-01 30 views
42

Đây là một điều thú vị. Tôi có một lớp A. Nó có một mục của lớp B, mà tôi muốn khởi tạo trong constructor của A sử dụng một danh sách initializer, như vậy:Ghi ngoại lệ từ danh sách khởi tạo của hàm tạo

class A { 
    public: 
    A(const B& b): mB(b) { }; 

    private: 
    B mB; 
}; 

Có cách nào để bắt ngoại lệ có thể được ném bởi nhà xây dựng bản sao của mB trong khi vẫn sử dụng phương pháp danh sách khởi tạo? Hoặc tôi sẽ phải khởi tạo mB trong các dấu ngoặc của hàm tạo để có một try/catch?

Trả lời

73

Có một chi của http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

Edit: Sau khi đào sâu thêm, chúng được gọi là "Chức năng thử khối".

Tôi thú nhận rằng tôi không biết điều này cho đến khi tôi tìm kiếm. Bạn học được điều gì đó mỗi ngày! Tôi không biết liệu đây có phải là bản cáo trạng về việc tôi sử dụng C++ như thế nào trong những ngày này, sự thiếu hiểu biết của tôi về C++, hoặc các tính năng thường xuyên của Byzantine làm nảy sinh ngôn ngữ. Ah tốt - tôi vẫn thích nó :)

Để đảm bảo mọi người không cần phải chuyển đến một trang web khác, cú pháp của một khối try chức năng cho nhà xây dựng hóa ra là:

C::C() 
try : init1(), ..., initn() 
{ 
    // Constructor 
} 
catch(...) 
{ 
    // Handle exception 
} 
+0

Ah ... có vẻ như chỉ là điều! –

+0

Ugh. Tôi không ngạc nhiên rằng có một số cách để làm điều đó, nhưng nó chắc chắn là một ví dụ tuyệt vời về lý do tại sao tôi ghét cú pháp khởi tạo C++ ... –

+14

LƯU Ý: bạn không thể xử lý ngoại lệ khi sử dụng chức năng thử khối trên các nhà xây dựng. ngay cả khi khối catch (...) của bạn không ném lại, ngoại lệ vẫn thoát cho người gọi. – Aaron

0

Tôi không thấy cách bạn làm điều đó với cú pháp danh sách khởi tạo, nhưng tôi cũng hơi hoài nghi rằng bạn sẽ có thể làm bất cứ điều gì hữu ích bằng cách bắt ngoại lệ trong hàm tạo của bạn. Nó phụ thuộc vào thiết kế của các lớp, rõ ràng, nhưng trong trường hợp nào bạn sẽ thất bại trong việc tạo ra "mB", và vẫn có một đối tượng "A" hữu ích?

Bạn cũng có thể để ngoại lệ thấm qua và xử lý nó bất cứ nơi nào hàm tạo cho A đang được gọi.

15

Nó không phải đặc biệt khá:

A::A(const B& b) try : mB(b) 
{ 
    // constructor stuff 
} 
catch (/* exception type */) 
{ 
    // handle the exception 
} 
4

Tôi biết đã có một thời gian kể từ khi cuộc thảo luận này bắt đầu. Nhưng cấu trúc try-and-catch được đề cập bởi Adam là một phần của tiêu chuẩn C++ và được hỗ trợ bởi Microsoft VC++ và GNU C++. Đây là chương trình hoạt động. Bằng cách này, catch sẽ tự động tạo ra một ngoại lệ khác để báo hiệu về lỗi khởi tạo.

#include <iostream> 
#include <exception> 
#include <string> 

using namespace std; 

class my_exception: public exception 
{ 
    string message; 
public: 
    my_exception(const char* message1) 
    { 
    message = message1; 
    } 

    virtual const char* what() const throw() 
    { 
    cout << message << endl; 
    return message.c_str(); 
    } 

    virtual ~my_exception() throw() {}; 
}; 

class E 
{ 
public: 
    E(const char* message) { throw my_exception(message);} 
}; 

class A 
{ 
    E p; 
public: 
    A() 
    try :p("E failure") 
    { 
      cout << "A constructor" << endl; 
    } 
    catch (const exception& ex) 
    { 
     cout << "Inside A. Constructor failure: " << ex.what() << endl; 
    } 
}; 


int main() 
{ 
    try 
    { 
     A z; 
    } 
    catch (const exception& ex) 
    { 
     cout << "In main. Constructor failure: " << ex.what() << endl; 
    } 
    return 0; 
} 
1

Mặc dù vậy, bạn có thể làm việc với khởi tạo lười biếng, giữ unique_ptr vào Reader trong MyClass và tạo nó bằng mới. Bằng cách đó, bạn thậm chí không cần cờ has_reader nhưng bạn chỉ có thể xem nếu unique_ptr của bạn là ban đầu hay không.

#include <iostream> 
#include <memory> 
using namespace std; 

class MyOtherClass 
{ 
public: 
    MyOtherClass() 
    { 
     throw std::runtime_error("not working"); 
    } 
}; 

class MyClass 
{ 
public: 
    typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr; 

    MyClass() 
    { 
     try 
     { 
      other = std::make_unique<MyOtherClass>(); 
     } 
     catch(...) 
     { 
      cout << "initialization failed." << endl; 
     } 

     cout << "other is initialized: " << (other ? "yes" : "no"); 
    } 

private: 
    std::unique_ptr<MyOtherClass> other; 
}; 

int main() 
{ 
    MyClass c; 

    return 0; 
} 

Tất nhiên, cũng có các giải pháp mà không sử dụng ngoại lệ nhưng tôi cho rằng đây là điều kiện tiên quyết trong cài đặt của bạn.

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