2016-10-06 6 views
6

В C++, следующий кодC++: Может ли "try {foo();} catch (...) {throw;}" быть оптимизирован для "foo();"?

try { 
    foo(); 
} catch (...) { 
    throw; 
} 

семантически идентичны просто звоню foo, как это?

foo(); 

Если да, то я могу ожидать внедренный компилятор, чтобы избежать первой версии до второй версии (при компиляции с оптимизацией включена)?

Другими словами, если я скомпилировать этот код с NDEBUG и оптимизации позволили

try { 
    foo(); 
} catch (...) { 
    assert(some_check()); 
    throw; 
} 

я могу предположить, что он никогда не должен быть медленнее, что это некрасиво версия

#ifndef NDEBUG 
    try { 
#endif 
    foo(); 
#ifndef NDEBUG 
    } catch (...) { 
    assert(some_check()); 
    throw; 
    } 
#endif 
+2

[Не на практике.] (Https://godbolt.org/g/kXdxf6) – Veedrac

+0

Я только угадываю здесь, но если ничего внутри foo() не генерирует исключение, можно с уверенностью предположить, что компилятор может сделать это оптимизация. – DeiDei

+2

@DeiDei Если 'foo' не может выбрасывать (и компилятор знает это, например, через' noexcept'), компилятор удалит все связанные ветви обработки исключений. Но вопрос более общий. – Veedrac

ответ

3

Нет, два не эквивалентны.

Независимо от того, расставлен ли стек, когда обработчик исключений не существует, определяется реализация ([except.handle] p9). Когда обработчик существует, но он просто перебрасывает исключение, стек должен быть разворачиван, по крайней мере, до момента, когда исключение повторно выбрано.

То есть:

struct S { ~S(); }; 
void foo() { S s; throw 0; } 
int main() { 
    try { foo(); } 
    catch(...) { throw; } 
} 

Это должно вызвать деструктор s «s. Когда try { ... } catch (...) { throw; } удален, больше не требуется вызывать деструктор s.

Это даже возможно, в зависимости от того, что делает деструктор s «s, для исполнения никогда не достичь повторного бросание исключения, путем добавления, например:

#include <stdlib.h> 
S::~S() { exit(0); } 

Теперь программа должна работать успешно, но когда удаляется try { ... } catch (...) { throw; }, это больше не требуется, и на реальных системах может произойти сбой.