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

У меня есть функция, которая работает с большим количеством данных, передаваемых в качестве аргумента приемника. мой BigData type уже поддерживает 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 как пожелаете. Однако в конечном решении следует попытаться свести к минимуму недостатки исходного кода, касающиеся эффективности и удобства использования.

10

Решение

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

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

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 звонки.

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

2

Другие решения

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

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

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

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

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

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

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

2

По вопросам рекламы [email protected]