LINUX.ORG.RU

Почему boost::optional еще не в стандартной библиотеке?

 , , ,


0

6

Я начал писать очередной хеллоуворлдный физзбазз, хочу написать функцию, которая находит путь в графе слов, если он там есть. Соответственно хочу вернуть или std::vector<std::string>, если путь найден, или ничего не возвращать. Что же мне теперь делать, тянуть буст в зависимостях? Или исключение кидать? А может что-то еще более наркоманское, типа умного указателя на этот самый вектор, и если не получилось, то указатель пусть будет равен нулю?

Ответ на: комментарий от hlebushek

А что создавать, если пустого значения у объекта, который иногда хотим возвращать, не бывает?

Значит, нужно подумать ещё раз и попробовать добить объект нулевым состоянием. Невозможность такого расширения для сложных объектов редка, а maybe и optional практически не нужны.

mashina ★★★★★
()

Этот ваш std::vector пустым не может быть что ли? :}

Deleted
()
Ответ на: комментарий от tailgunner

Чем этот optional лучше .size()?

Тем, что смотришь на тип результата и сразу всё понятно.

А если vector::size() вернулся равный нулю, то это не понятно?

andreyu ★★★★★
()
Ответ на: комментарий от Deleted

Глупости. Для этого и создана move-семантика. Указатель прячется внутри.

hlebushek ★★
() автор топика
Ответ на: комментарий от tailgunner

Тем, что смотришь на тип результата и сразу всё понятно.

Неясности становится ещё больше т.к. сразу не видно чем будет отличаться отсутствие вектора от нулевого вектора.

mashina ★★★★★
()
Ответ на: комментарий от andreyu

А если vector::size() вернулся равный нулю, то это не понятно?

Каким образом из типа результата становится понятно, что вектор нулевой длины - валидный результат, означающий «объект не найден»?

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Я же не лох, чтобы комментарии к функции читать. И так понятно, вон она вектор возвращает и всё, просто вектор. - так подумает каждый второй Васёк.

hlebushek ★★
() автор топика
Ответ на: комментарий от tailgunner

Каким образом из типа результата становится понятно, что вектор нулевой длины - валидный результат, означающий «объект не найден»?

Из типа никак. Но для меня очевидно, что если список пуст (size == 0), то поиск не нашел объект.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Но для меня очевидно, что если список пуст (size == 0), то поиск не нашел объект.

Совершенно не обязательно. К примеру, если список файлов в директории пуст, то это результат поиска в пустой директории, или поиск вообще ещё не стартовал?

Какое нулевое значение выбрать для идентификатора, 0, -1 или некая константа?

К примеру, есть знаковое целое, как мне проверить было ли оно уже инициализировано или ещё нет, если все значения из диапазона могут быть валидны?

Я навскидку могу вспомнить кучу случаев когда запиливал конструктор по-умолчанию в структуру и метод isNull(). С одной стороны не хочется заранее пессимизировать программу, бесполезно выделяя мелкие структуры в куче, с другой стороны замусоривается код и ломается принцип RAII. С optional же все эти проблемы исчезают.

Dendy ★★★★★
()

Почему boost::optional еще не в стандартной библиотеке?

Потому что в коммитете не смогли согласиться на счёт какой-то маленькой детали и не успели к C++14. Но уже приняли для C++17. Есть и отдельные реализации: https://github.com/vlovich/Optional. В GCC можно проверить <experimental/optional> header.

С std::variant тоже было не всё гладко. Не могли прийти к одному мнению насчёт того, нужно ли пустое состояние объекта std::variant, и что делать когда move конструктор выбросит исключение.

rupert ★★★★★
()

Возвращай char**. Если не нашёл — возвращай NULL. Находят же себе люди проблемы на ровном месте.

Legioner ★★★★★
()
Ответ на: комментарий от andreyu

для меня очевидно, что если список пуст (size == 0), то поиск не нашел объект.

Или результат ошибочен?

И optional - он несколько более широкого назначения.

tailgunner ★★★★★
()

Да блин, ТС-у с его вектором строк, можно было бы обойтись старым дедовским способом:

bool find_path(..., std::vector<std::string> & path_receiver) {
  ...
  if(path_found) {
    path_receiver = ...;
    return true;
  }
  return false;
}
...
std::vector<std::string> path;
if( find_path(..., path) ) {
  ... // do something with path's content
}

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Вообще-то RVO теперь прописано в стандарте.

Где в стандарте прописана обязанность реализации выполнять эту оптимизацию?

tailgunner ★★★★★
()

может что-то еще более наркоманское

Странно, уже вторая страница тредика, а выставлять errno еще не посоветовали

Deleted
()
Ответ на: комментарий от tailgunner

Где в стандарте прописана обязанность реализации выполнять эту оптимизацию?

Эту - это какую? RVO в современном С++ включает два варианта оптимизации: copy elision и move. Если прописанные в стандарте условия для copy elision соблюдены, а компилятор не осилил, он обязан сделать move (при наличии move constructor).

Простым языком: http://en.cppreference.com/w/cpp/language/copy_elision

cppreference

If copy elision cannot be performed, the return statement will attempt to use the move constructor to initialize the by-value return object (even if the argument of the return statement is lvalue), and only if that is unavailable, a copy would be performed. (since C++11)

То же самое в типичной для стандарте витиеватой форме:

стандарт

When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. — end note ]

anonymous
()

Врёшь. std::experimental::optional есть и в libstdc++ и в libc++. А до него спокойно обходились bool FindPath(std::vector<std::string>&).

slovazap ★★★★★
()
Ответ на: комментарий от Dendy

К примеру, если список файлов в директории пуст, то это результат поиска в пустой директории,

Результат поиска - «ничего не найдено» от этого как-то меняется?

или поиск вообще ещё не стартовал?

Программист не знает, стартовал он поиск или нет?

Какое нулевое значение выбрать для идентификатора, 0, -1 или некая константа?

Понятие «нулевое значение» - это ноль. Млять, ровно ноль.

К примеру, есть знаковое целое, как мне проверить было ли оно уже инициализировано или ещё нет, если все значения из диапазона могут быть валидны?

Как это вообще относится к теме задачи?

С optional же все эти проблемы исчезают.

Еще раз, как это поможет решить данную в топике задачу? Попытка усложнять приводит к появлению монстров а-ля 3ds max, которые вроде и могут многое, а по факту валятся на простейших операциях. Но да, «настоящий с++» во все поля.

andreyu ★★★★★
()
Ответ на: комментарий от tailgunner

Или результат ошибочен?

Что в контексте поставленной задачи означает «результат ошибочен»?

И optional - он несколько более широкого назначения.

Именно, и для данной задачи он нафиг не нужен.

andreyu ★★★★★
()

фрактал плохого дизайна
и эти люди ещё что-то говорят про пхп

Bad_ptr ★★★★★
()
Ответ на: комментарий от andreyu

Что в контексте поставленной задачи означает «результат ошибочен»?

Что функция поиска маршрута вернула вектор нулевой длины в результате ошибки.

для данной задачи он нафиг не нужен.

Смотря как формулировать задачу.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Что функция поиска маршрута вернула вектор нулевой длины в результате ошибки.

Ну так не нужно люто гогнокодить, тогда вероятность такого события будет не выше возврата неполного пути. В любом случае проверка на неполную отработку должна быть в самой ф-ии поиска и реализовать её можно легко без optional во внешнем интерфейсе.

mashina ★★★★★
()
Ответ на: комментарий от tailgunner

Что функция поиска маршрута вернула вектор нулевой длины в результате ошибки.

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

Смотря как формулировать задачу.

Задача уже сформулирована.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Что функция поиска маршрута вернула вектор нулевой длины в результате ошибки.

Тогда разработчику нужно исправить функцию поиска

Да, Капитан. Конечно, нужно.

Задача уже сформулирована.

Возможно. Но это твоя личная формулировка, которой ты не поделился.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Да, Капитан. Конечно, нужно.

Зачем тогда вы предлагаете обмазываться костылями и подпорками?

Возможно. Но это твоя личная формулировка, которой ты не поделился.

Какая моя личная формулировка? У вас закуска кончилась, а праздник продолжается?

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Зачем тогда вы предлагаете обмазываться костылями и подпорками?

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

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

Усложнение кода далеко не самый лучший способ облегчить обнаружение ошибок.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Усложнение кода далеко не самый лучший способ облегчить обнаружение ошибок.

Особое значение векторов нулевой длины тоже усложняет код. А если попытаться распространить это правило на другие объекты - код превратится в ребус.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Особое значение векторов нулевой длины тоже усложняет код. А если попытаться распространить это правило на другие объекты - код превратится в ребус.

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

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Домыслами занимаетсь вы оба. Стоило бы для начала уточнить, может ли быть путь нулевой длины (e.g. путь в графе от узла к этому же узлу имеет нулевую длину, но фиг знает, что там у ТС за задача).

anonymous
()
Ответ на: комментарий от anonymous

Стоило бы для начала уточнить, может ли быть путь нулевой длины

В топике поставлено четкое условие:

Соответственно хочу вернуть или std::vector<std::string>

Если путь найден, то вектор будет содержать как минимум один элемент.

andreyu ★★★★★
()
Последнее исправление: andreyu (всего исправлений: 1)
Ответ на: комментарий от andreyu

Если путь найден, то вектор будет содержать как минимум один элемент.

Если у ТС возможна ситуация, когда ищется путь из вершины A в вершину A (т.е. в саму себя), то путь из A в A есть, но он имеет нулевую длину. Это совсем другая ситуация по сравнению с поиском пути из A в B, когда A и B вообще не связаны друг с другом.

eao197 ★★★★★
()
Ответ на: комментарий от andreyu

Если вектор нулевой длины, то путь не найден.

Ты сказал то же, что и я, но другими словами. Думаю, рано или поздно ты поймешь, зачем нужен optional, сформулируешь это по-своему, и будешь защищать с таким же высокомерным упрямством, с которым сейчас объявляешь его ненужным.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ну возвращать -1 может и слишком хорошо, но в возврате пустого вектора не вижу ничего плохого. Ведь пустой вектор тут не является валидным значением. Оptional (именно) тут, как по мне, только всё усложнит.

DarkEld3r ★★★★★
()

Еще один аргумент за boost::optional и против вектора нулевой длины: с boost::optional нельзя проигнорировать отсутствие результата и попытаться итерировать этот вектор нулевой длины, не проверив, есть ли в нем что-то.

hlebushek ★★
() автор топика
Ответ на: комментарий от hlebushek

это не аргумент
можно как раз сделать так чтобы и ошибочное значение было «правильным»
просто при итерации по пустому списку ничего не будет вычисляться
а код упростится и не будет лишних развесистых ветвлений

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

Если пустой optional попытаются использовать как вектор слов, то почти наверняка (за исключением разве что каких-нибудь преобразований к bool) получится исключение, и ничего непонятного и странного не произойдет. А вот с пустым вектором вполне может быть, что где-нибудь там результата не будет, и что-то просто тихо не добавится в другой список слов, и программа отработает и выдаст какой-то результат в правильном формате, но результат будет неправильный.

Таким образом boost::optional-способ лучше соответствует принципу fail early.

hlebushek ★★
() автор топика
Ответ на: комментарий от hlebushek

Если пустой optional попытаются использовать как вектор слов, то почти наверняка (за исключением разве что каких-нибудь преобразований к bool) получится исключение, и ничего непонятного и странного не произойдет.

Это UB и так делать нельзя. Правильный код будет выглядеть как-то так (пусть optional имеет move конструктор)

if (auto path = Find(...)) {
    if (!*path) {
        /* нулевой вектор, невалидное состояние ? */
    }
    ...
} else {
    ...
} 
Итого, имеем три ветки если нулевой вектор является невалидным состоянием и две в ином случае. optional не помог сделать код безопаснее т.к. нулевой вектор всё равно не отсекается, а если он является валидным, то реализуются твои фобии

А вот с пустым вектором вполне может быть, что где-нибудь там...

Если использовать только вектор с валидным нулевым состоянием, то будет аналогичный код с двумя ветками в котором нет проверки на потенциальные ошибки выполнения Find(...)

if (auto path = Find(...)) {
    /* что-то нашли, работаем дальше */
} else {
    /* ничего не нашли, пичалимся */
} 

Таким образом boost::optional-способ лучше соответствует принципу fail early.

Получается всё ровно наоборот. Как видишь из примера выше, код с optional откладывает обнаружение ошибки за пределы Find(). К моменту обнаружения проблемы объекта виновника торжества, или контекста из которого был получен результат, может уже не существовать что затруднит отладку.

Вариант же с валидным нулевым вектором и без optional не позволяет получить дополнительные данные о корректности работы Find() и, следовательно, заставляет разработчика делать их прямо на месте потенциального возникновения, т.е. в Find(). Таким образом ошибка обнаруживается значительно раньше, в контексте возникновения, и код становится проще для анализа без optional.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Какой нафиг пустой вектор в optional? Да и вообще у std::vector нет ни operator!, ни оператора приведения к bool.

hlebushek ★★
() автор топика
Ответ на: комментарий от hlebushek

Какой нафиг пустой вектор в optional?

Очевидно, вектор нулевого размера()

Да и вообще у std::vector нет ... оператора приведения к bool.

Да, но от этого суть не меняется.

mashina ★★★★★
()

/me просмотрел первую половину треда и взялся за голову. Может я чего-то не понимаю, но... Пустой вектор! Тогда любой проход по вектору даст пустое множество, что, как я понял из ТЗ, является корректным.

Это в данном частном случае, когда «особое» значение укладывается в возвращаемый тип и не приводит к большому количеству if'ов.

А если вообще, то это ж типовой кейс для исключения! Что может быть проще исключения?

Kroz ★★★★★
()
Ответ на: комментарий от mashina

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

Ты готов уродовать обьекты костылями только бы не использовать optional? А почему? Чем он тебе не угодил настолько?

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.