Try {....} catch (..), только если определенное выражение времени компиляции истинно

Вот что мы пытаемся сделать

try {
    std::uninitialized_copy(...);
} catch(...) {
    if(!boost::has_trivial_destructor<T>::value) {
       // some cleanup to do here...
    }
    throw;
}

Мы задаемся вопросом, имеет ли значение try/catch стоимость, если константа времени компиляции в if является ложной.

Может ли компилятор в своих правах "как-если" удалить попытку catch и вести себя как-будто вызов std::uninitialized_copy появился без try вокруг него?

Или есть что-то скрытое в спецификациях С++, которое требует, чтобы компилятор оставил его здесь? В качестве примера представьте гипотетическую функцию surrounding_try_blocks(), которая возвращает динамическое окружение try try, отсчитываемое в настоящее время вокруг кадра.

Ответ 1

Я не знаю, что сделает компилятор, но я знаю, что вы можете обеспечить оптимизацию самостоятельно:

template <class T>
typename boost::enable_if_t<boost::has_trivial_destructor<T>::value, void>
wrap_uninitialized_copy (...) {
    std::uninitialized_copy(...);
}

template <class T>
typename boost::enable_if_t<!boost::has_trivial_destructor<T>::value, void>
wrap_uninitialized_copy (...) {
    try {
        std::uninitialized_copy(...);
    } catch(...) {
        // some cleanup to do here...
        throw;
    }
}

Ответ 2

Ниже я обобщил стоимость использования исключения, которое я сопоставил из разных источников. Как то, что вы просите в своем втором пункте, мне не очень понятно. Поэтому я подумал, что лучше всего через тебя все. Надеюсь, вы поймете что-то важное.

Чтобы обрабатывать исключения во время выполнения, программы должны выполнять значительную сумму бухгалтерского учета. В каждый момент они должны иметь возможность идентифицировать объекты, требующие уничтожения, если выбрано исключение; они должны обратить внимание на каждую запись и выйти из блока try; и для каждого блока try они должны отслеживать связанные клаузулы catch и типы исключений, которые могут обрабатывать эти статьи.

Есть вещи, за которые вы платите, даже если вы никогда не используете какие-либо функции обработки исключений. Вы платите за пространство, используемое структурами данных, необходимое для отслеживания того, какие объекты полностью построены, и вы платите за время, необходимое для обновления данных данных. Эти затраты обычно довольно скромны.

Тем не менее, программы, скомпилированные без поддержки исключений, как правило, быстрее и меньше, чем их аналоги, скомпилированные с поддержкой исключений

Ответ 3

Из 15.1/8 находим

Выражение-выражение без операндов возвращает текущую обработку исключение (15.3). Исключение возобновляется с использованием существующих временный; не создается новый объект временного исключения...

Для меня это довольно ясно означает, что если предположить, что оценка boost::has_trivial_destructor<T>::value тривиально может не иметь побочных эффектов, компилятор должен иметь возможность легко определить, что вся основная часть улова не может быть выполнена и что весь конструкцию можно оптимизировать. Я не знаю конкретного компилятора, который делает/не делает этого, однако.

Мое единственное (небольшое) сомнение заключается в том, считает ли язык, что очистка и сброс std::uncaught_exception() попадают в предложение "как-если".