2008-10-01 19 views
42

Oto ciekawa. Mam klasy A. Posiada element klasy B, którego chcę, aby zainicjować w konstruktorze A, stosując listę initializer, tak:Łapanie wyjątków z listy inicjalizacyjnej konstruktora

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

    private: 
    B mB; 
}; 

Czy istnieje sposób, aby złapać wyjątki, które mogą zostać wyrzucone według konstruktora kopiowego mB przy użyciu metody listy inicjalizacyjnej? Czy musiałbym zainicjować mB w nawiasach konstruktora, aby uzyskać próbę/catch?

Odpowiedz

73

Mają lektury http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)

EDIT: Po więcej kopania nazywane są one „Funkcja spróbować bloki”.

Przyznaję, że nie wiedziałem o tym, dopóki nie poszedłem szukać. Każdego dnia uczysz się czegoś! Nie wiem, czy to jest oskarżenie o to, jak rzadko używam C++ w dzisiejszych czasach, mój brak wiedzy w C++, czy często bizantyjskie funkcje, które zaśmiecają ten język. Ah dobrze - ja nadal go lubię :)

celu zapewnienia ludzie nie muszą przejść do innej strony, składni funkcji bloku try dla konstruktorów okazuje się być:

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

Ah ... to wygląda jak coś! –

+0

Ugh. Nie jestem zaskoczony, że jest jakiś sposób, aby to zrobić, ale z pewnością jest to świetny przykład, dlaczego nienawidzę składni inicjalizatora C++ ... –

+14

UWAGA: nie można obsłużyć wyjątku podczas używania bloków try function na konstruktorach. nawet jeśli blok catch (...) nie jest ponownie rzutowany, wyjątek nadal ucieka do osoby dzwoniącej. – Aaron

0

Nie widzę sposobu, w jaki można to zrobić za pomocą składni listy inicjalizacyjnej, ale jestem też nieco sceptyczny, że będziesz w stanie zrobić cokolwiek pożytecznego, wychwytując wyjątek w swoim konstruktorze. Oczywiście zależy to od projektu klas, ale w jakim przypadku nie uda ci się stworzyć "mB" i nadal będziesz miał użyteczny obiekt "A"?

Równie dobrze możesz pozwolić, aby wyjątek był przesiąknięty i obsłużyć go wszędzie tam, gdzie wywoływany jest konstruktor.

15

To nie jest szczególnie pretty:

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

Wiem, że minęło trochę czasu od rozpoczęcia tej dyskusji. Ale wspomniana przez Adama konstrukcja "try-and-catch" jest częścią standardu C++ i jest obsługiwana przez Microsoft VC++ i GNU C++. Oto program, który działa. Nawiasem mówiąc, haczyk generuje automatycznie inny wyjątek do sygnalizowania awarii konstruktora.

#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

Można pracować z leniwej inicjalizacji, mimo, że jest posiadać unique_ptr dla czytelnika w MojaKlasa i utworzyć nowe. W ten sposób nie potrzebujesz nawet flagi has_reader, ale możesz zobaczyć, czy twoja unikalna_ptr jest początkowa czy nie.

#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; 
} 

Oczywiście istnieją również rozwiązania bez używania wyjątków, ale założyłem, że jest to warunek wstępny w ustawieniach.

Powiązane problemy