TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #40 1.08K
std::optional

Сталкивались ли с необходимостью определить особенное состояние переменной, которая может принимать разные значения?

Приведу пример из практики. Недавно мне нужно было придумать интерфейс для передачи необязательных целочисленных параметров в функцию. В данном контексте особенным состоянием является отсутствие одного или нескольких значений.

Как вообще можно теоретические решить подобную проблему? Мне пришли в голову следующие варианты:
1. Определить несколько реализаций функций
Крайне неудобный способ, необходимо проверять всевозможные комбинации переменных и под них писать реализации функций.

2. Использовать специальную константу
Специально заданное значение может быть одним из возможных значений, которые передал пользователь, хоть и крайне редким. А вам, как коллегам автора решения, было бы удобно искать специально подобранные константы для ваших новых реализаций?

3. Передавать std::map с параметрами
Неудобное обращение и проверка существования ключа мапы. Накладные расходы на хранение и обслуживание структуры.

4. Передавать указатели на значения
Такой способ может показаться удобным, т.к. nullptr однозначно определяет отсутствие значения. Неудобно, что можно случайно забыть сделать проверку и словить segfault 🥲

5. Использовать специальный класс
Именно этот способ я и выбрал для себя. Давайте расскажу подробнее ниже.

В стандарте языка существует шаблонный класс std::optional<T>, который предоставляет разработчику возможность зарезервировать память под объект класса T и отложить момент инициализации, вплоть до бесконечности. Пользователь имеет возможность узнать состояние объекта и получить к нему доступ. В случае попытки получить доступ к объекту в невалидном состоянии будет брошено исключение std::bad_optional_access (лучше, чем не отлавливаемый segfault 😉).

По сути этот класс представляет из себя обертку над внутри лежащим классом, который добавляет специальное логическое поле для сохранения состояния объекта - инициализировано или нет. Объект std::optional резервирует память под объект класса T там, где его аллоцировали - на стеке или куче, как std::array. Это совсем немного увеличивает расход памяти (+1 байт) и выравнивает полученную структуру.

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

Пример: https://compiler-explorer.com/z/65KrTnjbe

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

#cpp17 #STL
  • ❤ 20
  • 🔥 6
  • 👍 3
  • 👏 1
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →