Jste zde

Méně známé skutečnosti o C++: try-catch blok jako tělo funkce

C++ umožňuje, abyste u těla funkce, která obsahuje pouze try-catch blok, vynechali okolní složené závorky ("{" a "}"). V tomto příspěvku se podíváme na to, jak to vypadá a k čemu je to použitelné.

O co jde?

Vezměme si následující kus kódu:

int foo() {
    try {
        // ... (1)
    } catch (...) {
        // ... (2)
    }
}

Pokud funkci zavoláme a v místě (1) dojde k vyhození výjimky, tak se výjimka odchytí a pokračuje se v místě (2). Pokud je funkce tvořena pouze takovýmto try-catch blokem, tak C++ standard (viz sekce 15) jím umožňuje nahradit tělo funkce:

int foo()
try {
    // ... (1)
} catch (...) {
    // ... (2)
}

Chování bude totožné.

Huh. K čemu to je?

Že to ušetří jednu úroveň odsazení asi napadne každého. Existuje ale případ, kdy toto použít musíme? Ano. Uvažujte následující třídu.

class A: public B {
public:
    A() {
        // ... (X)
    }
 
private:
    C c;
};

Jak jistě víte, tak v konstruktoru třídy A se provedou dvě věci. První je, že se zavolá konstruktor bázové třídy B. Druhá je zavolání konstruktoru třídy C. Konstruktor tedy můžeme přepsat do následujícího tvaru:

A(): B(), c() {
    // ... (X)
}

Co když ale konstruktor třídy B či C vyhodí výjimku? Jak ji odchytit? Následující přístup selže:

A(): B(), c() {
    try {
        // (X)
    } catch (...) {
        // ... obsluha
    }
}

Důvodem je, že konstruktory B a C se provedou ještě před tělem konstruktoru A, takže když dojde k vyhození výjimky, naše obsluha se nezavolá. Co nám tedy standard umožňuje udělat, je následující:

A() try : B(), c() {
    // ... (X)
} catch (...) {
    // ... obsluha
}

A voalá, pokud B() či c() vyhodí výjimku, tak se korektně zavolá naše obsluha. Pokud by vás zajímaly detaily (např. co všechno lze v obsluze udělat), tak doporučuji mrknout na tento článek.

Komentáře

Zdravím, nepřebývá u poslední ukázky kódu '}' navíc?

Ano, děkuji za upozornění. Opravil jsem to.

Přidat komentář