Принимайте аргументы и перемещайте семантику для функций, которые могут потерпеть неудачу (строгое исключение безопасности)

У меня есть функция, которая работает с большим количеством данных, передаваемых в качестве аргумента приемника. мой BigData Тип уже поддерживает C++11 и поставляется с полностью функциональным конструктором перемещения и реализациями перемещения, так что я могу уйти, не копируя эту чертову вещь:

Result processBigData(BigData);

[...]

BigData b = retrieveData();
Result r = processBigData(std::move(b));

Это все прекрасно работает. Тем не менее, моя функция обработки может иногда не работать во время выполнения, что приводит к исключению. Это на самом деле не проблема, так как я могу просто исправить вещи и повторить попытку:

BigData b = retrieveData();
Result r;
try {
    r = processBigData(std::move(b));
} catch(std::runtime_error&) {
    r = fixEnvironmnentAndTryAgain(b);
    // wait, something isn't right here...
}

Конечно, это не сработает.

Поскольку я переместил свои данные в функцию обработки, к тому времени, когда я прибуду в обработчик исключений, b больше не будет использоваться

Это грозит радикально снизить мой энтузиазм по поводу передачи аргументов в стоимостном выражении.

Итак, вот вопрос: как справиться с такой ситуацией в современном коде C++? Как получить доступ к данным, которые ранее были перемещены в функцию, которая не была выполнена?

Вы можете изменить реализацию и интерфейсы для обоих BigData а также processBigData как пожелаете. Однако в конечном решении следует попытаться свести к минимуму недостатки исходного кода, касающиеся эффективности и удобства использования.

2 ответа

Решение

По всей видимости, этот вопрос активно обсуждался на недавнем CppCon 2014. Херб Саттер кратко изложил последние события в своем заключительном выступлении " Назад к основам! Основы современного стиля C++ (слайды).

Его вывод довольно прост: не используйте передачу по значению для аргументов поглотителя.

Аргументы в пользу использования этого метода в первую очередь (как его популяризовал Эрик Ниблер, C++ 2013, лейтмотив C++11, дизайн библиотеки (слайды)), похоже, перевешиваются недостатками. Первоначальной мотивацией для передачи аргументов-приемников по значению было избавление от комбинаторного взрыва для перегрузок функций, возникающих в результате использования const& / &&,

К сожалению, похоже, что это приводит к ряду непреднамеренных последствий. Одним из них являются потенциальные недостатки эффективности (в основном из-за ненужных распределений буфера). Другая проблема заключается в исключении безопасности из этого вопроса. Оба из них обсуждаются в разговоре Херб.

Вывод Херба состоит в том, чтобы не использовать передаваемое значение для аргументов, а вместо этого полагаться на отдельные const& / &&const& быть по умолчанию и && зарезервировано для тех немногих случаев, когда требуется оптимизация).

Это также соответствует тому, что предложил ответ @Potatoswatter. Передав аргумент раковины через && мы могли бы отложить фактическое перемещение данных от аргумента до точки, где мы можем дать гарантию без исключения.

Мне в некотором роде понравилась идея передачи аргументов по значению, но, похоже, на практике это не так хорошо, как все надеялись.

Я так же в замешательстве от этой проблемы.

Насколько я могу судить, лучшая на сегодняшний день идиома - разделить передачу по значению на пару ссылок по ссылкам.

template< typename t >
std::decay_t< t >
val( t && o ) // Given an object, return a new object "val"ue by move or copy
    { return std::forward< t >( o ); }

Result processBigData(BigData && in_rref) {
    // implementation
}

Result processBigData(BigData const & in_cref ) {
    return processBigData( val( in_cref ) );
}

Конечно, кусочки аргумента могли быть перемещены до исключения. Проблема распространяется на что угодно processBigData звонки.

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

Другие вопросы по тегам