C++11: возвращает ли объект по значению никогда не генерирует исключения, когда определяется ctor перемещения?
В C++11 и более поздних стандартах гарантируется, что ctor копии (возможно, выбрасывающий исключение) не вызывается при возврате объекта класса по значению из функции - при условии, что ctor перемещения определен для этого класса? Фон: Предположим,
struct X {
X() {}
X(const X&) {/* code that might throw exceptions */}
X(X&&) {/* code that never throws exceptions */}
...
};
а также
X my_func(some_type& t)
{
X x;
// code that modifies t and x but never throws exceptions
return x;
}
Теперь, например, такое выражение, как
some_other_func(my_func(t));
никогда не выбрасывать исключения (т.е. это гарантировано?) при условии, что функция some_other_func(const X&)
не бросает исключения? А что если подпись some_other_func
мы some_other_func(X)
?
2 ответа
Правило простое: функция обрабатывается так, как будто она может генерировать исключения, если она не помечена как функция, которая не может. Конструктор перемещения является функцией, аналогичной любой другой в этом отношении. Когда определено вручную, это считается потенциально бросающим, если не определено noexcept
,
Неявно дефолтные функции (т.е. автоматически предоставляемые операции копирования и перемещения) обычно следуют логике: объявлено как noexcept
тогда и только тогда, когда все функции, которые он вызывает, noexcept
,
Исключения никогда не генерируются спонтанно в правильно сформированной программе C++, которая только оправдывает определенное поведение.
Если ваш код представляет собой правильно сформированную программу, вы никогда не вызываете или не взаимодействуете с какой-либо функцией языка или библиотеки, которой разрешено генерировать исключения, и код, который вы пишете, не генерирует исключения (явным образом), тогда результатом будет код, который не будет генерировать исключения,
Если вы не пометите свои функции и методы как noexcept
компилятор и стандартная библиотека могут этого не понимать и могут предполагать, что ваш код генерирует исключения (даже если это невозможно). В некоторых случаях это может привести к тому, что компилятор выделит память и сгенерирует исключение из-за того, что ваш код может вызвать исключение или вызвать другой метод (например, копировать вместо перемещения, например, в определенных векторных операциях).
Что вы должны сделать, это пометить X(X&&)
а также X()
как noexcept
и эта конкретная проблема уходит.
Несмотря на это, ваш точный код не выдаст, если some_other_function
не берет X
но вместо этого тип, созданный из X
и эта операция может бросить, или тело some_other_function
мог бы бросить.