Подтвердить что ты не робот

Когда использовать boost:: optional и когда использовать std:: unique_ptr в случаях, когда вы хотите реализовать функцию, которая может возвращать "ничего"?

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

* - мы игнорируем исходную версию ptr, пару с флагом bool и исключение, когда ни одна найденная версия.

boost::optional<Person> findPersonInList();

или

std::unique_ptr<Person> findPersonInList();

Так есть ли какие-то причины предпочесть друг другу?

4b9b3361

Ответ 1

Это зависит от того, хотите ли вы вернуть дескриптор или копию.

Если вы хотите вернуть дескриптор:

  • Person*
  • boost::optional<Person&>

являются приемлемыми. Я склонен использовать класс Ptr<Person>, который бросает в случае нулевого доступа, но это моя паранойя.

Если вы хотите вернуть копию:

  • boost::optional<Person> для не-полиморфных классов
  • std::unique_ptr<Person> для полиморфных классов

поскольку динамическое распределение несет накладные расходы, поэтому вы используете его только при необходимости.

Ответ 2

Общий ответ: ваши намерения выражаются boost::optional, а не std::unique_ptr. Тем не менее, ваш частный случай операции find должен, вероятно, соответствовать стандартным библиотечным способом его выполнения, предполагая, что ваш базовый тип имеет концепцию итераторов: возвратите итератор в end(), если ни один элемент не найден, и итератор к элементу в противном случае.

Ответ 3

boost::optional более четко указано ваше намерение. Вам нужно явно указать, что пустой std::unique_ptr означает, что нет значения для возврата

Ответ 4

Существует четвертый способ сделать это: заставить функцию генерировать исключение, если ничего не найдено.

Я знаю, что это на самом деле не отвечает на ваш вопрос, и поэтому я извиняюсь, но, возможно, вы об этом не думали.

Ответ 5

А, Xeo еще не появился?

Хорошо, я сказал вам это один раз, и я расскажу еще раз: эти два являются совершенно разными объектами в разных целях.

  • unique_ptr означает, что у меня есть объект. Это просто другой способ сказать: "Я - объект". Таким образом, null unique_ptr - это то, что может привлечь внимание. Я ожидал объект, но ничего не получил; код должен быть неправильным!
  • optional означает, что иногда я не инициализирован, но это нормально. В этом случае нет беспокойства; если он None, это поведение, о котором думали.

Тот факт, что оба неявно конвертируются в bool, не означает, что они могут быть использованы с возможностью перезарядки. Используйте optional с кодом, который, скорее всего, не приведет к выходу (например, чтение потока). Используйте unique_ptr в объектах factory; они, скорее всего, создадут для вас объект, а если нет, создайте исключение.

Вывод, касающийся вашего примера: find должен возвращать optional.

Ответ 6

Концептуально сводится к этому, учитывая требование обнуляемости:

std::optional имеет семантику значений, хранилище стека.

std::unique_ptr имеет семантику перемещения, кучу хранилища.

Если вы хотите семантику значений и кучу хранилища, используйте std::indirect http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf.

(Если вы хотите переместить семантику и хранилище стека... Я не знаю. Я предполагаю, что это уникальный_ptr с распределителем стека?)

Ответ 7

Так есть ли какие-то причины предпочесть друг другу?

Они выражают совсем другое намерение: optional говорит, что функция не может дать результат, чтобы дать вам (и это не ошибка). unique_ptr сообщает вам что-то о семантике владения (и более приемлемо использовать с null, чтобы выразить ошибку).

Обычно я бы использовал тот, который лучше всего отражает намерение интерфейса.

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

Я бы сказал это с помощью optional, чтобы было ясно, что функция может ничего не возвращать (и не возвращать что-либо не является случаем ошибки).

В случае, если мой синтаксический анализ должен был проверять данные (например, парсер регулярных выражений должен давать ошибку, если выражение синтаксического анализа является недопустимым регулярным выражением) Я бы вернул null unique_ptr или, еще лучше, исключил исключение.