Кто управляет исключением, генерируемым конструктором копирования в параметрах?

Предположим, у меня есть эта функция

void foo() noexcept
{
   // Safely noexcept code.
}

И затем этот класс:

class Bar
{
   Bar(const Bar&) { ... } // Is not noexcept, so might throw
   // Non movable:
   Bar(Bar&&) = delete;
};

Теперь мне нужно изменить foo(), чтобы получить Bar по значению:

void foo(Bar bar) // noexcept?
{
   // Safely noexcept code
}

Я предполагаю, что копирование Bar выполняется до вызова foo, поэтому теоретически код foo все еще может быть noexcept, но я не уверен, как это определяется на уровне C++. Должен ли foo удалить noexcept или это вызывающий абонент, который может выбросить при копировании Bar? Зависит ли это от режима вызова (stdcall, farcall и т. д.) или компилятора? Обновление: в других вопросах я не нашел ссылок на соглашение о вызовах. Это должно повлиять на поведение. Я полагаю.


person LeDYoM    schedule 20.09.2019    source источник
comment
foo может остаться noexcept. копирование (если есть) происходит до вызова.   -  person Jarod42    schedule 20.09.2019
comment
@jarod42 jarod42, но разве это не зависит от соглашения о вызовах компилятора?   -  person LeDYoM    schedule 20.09.2019


Ответы (2)


См. [expr.call]/4:

Инициализация и уничтожение каждого параметра происходит в контексте вызывающей функции. [ Пример: Доступ к конструктору, функциям преобразования или деструктору проверяется в точке вызова в вызывающей функции. Если конструктор или деструктор для параметра функции выдает исключение, поиск обработчика начинается в области действия вызывающей функции; в частности, если вызываемая функция имеет блок function-try-block (пункт 18) с обработчиком, который может обрабатывать исключение, этот обработчик не рассматривается. —конец примера ]

Поэтому вы все еще можете пометить foo noexcept, даже если инициализация bar может привести к ошибке. Вызывающая функция не должна быть noexcept. (То есть, если вы не согласны с завершением программы в случае исключения.)

person Brian Bi    schedule 20.09.2019
comment
Как там с инициализацией возвращаемых значений? - person Daniel Langr; 20.09.2019
comment
Я бы добавил еще одно замечание, что даже оценка параметров по умолчанию происходит в контексте вызывающей стороны. - person 6502; 20.09.2019
comment
@DanielLangr Это следует задать как новый вопрос. - person Brian Bi; 20.09.2019

Построение параметров происходит в вызывающей программе; как только все параметры построены/преобразованы, вызывается функция.

Что-то, что может быть неочевидным, заключается в том, что в C++ даже выражение значения по умолчанию для непереданных параметров происходит в вызывающем объекте: т.е.

void foo(MyClass x=MyClass()) {
    ...
}

конструкция на случай

foo();

по-прежнему выполняется на вызывающем сайте до фактического вызова функции.

person 6502    schedule 20.09.2019