Имеет ли смысл объединить опцию с reference_wrapper?

Мне пришло в голову, что в C++ можно использовать тип std::optional<std::reference_wrapper<T>>. Объект этого типа по существу является ссылкой на объект типа T или нулевое значение, то есть в значительной степени указатель. Мои вопросы:

  1. Существует ли какая-либо концептуальная разница между std::optional<std::reference_wrapper<T>> и T*?

  2. Есть ли какая-то практическая разница? Существуют ли ситуации, когда было бы целесообразно выбрать std::optional<std::reference_wrapper<T>> over T*?

Ответ 1

Существует ли какая-либо концептуальная разница между std::optional<std::reference_wrapper<T>> и T*?

std::optional<>, как уже указывает название, предназначено для использования, когда мы можем иметь значение или вообще не иметь никакого значения.

Эквивалент, не имеющий значения для объекта T*, будет присваивать ему nullptr, т.е. Указатель укажет на никуда, в отличие от где-нибудь (или даже где-нибудь, т.е. Неинициализированного). Можно сказать, что std::optional<> экспортирует концепцию nullptr для указателей на любой произвольный тип. Итак, я бы сказал, что они концептуально очень похожи, поскольку std::option<> подходит к своего рода обобщению.

Есть ли какая-то практическая разница? Существуют ли ситуации, когда было бы целесообразно выбрать std::optional<std::reference_wrapper<T>> over T*?

Я могу думать о размере. std::optional<> содержит внутренний флаг для указания наличия/отсутствия значения, тогда как для T* значение nullptr кодируется непосредственно как одно из значений, которое может хранить указатель. Таким образом, объект std::optional<std::reference_wrapper<T>> будет больше, чем T*.

Когда дело доходит до безопасности, в отличие от T*, std::optional<> предоставляет value() функции-члена value() которое генерирует исключение, если нет значения (он предоставляет, а также небезопасный operator*() как это делает T*).

Кроме того, используя std::optional<std::reference_wrapper<T>> вместо T*, например, как возвращаемое значение функции, может указывать более явным образом, что вообще не может быть никакого значения.

Ответ 2

Основное различие между std::optional<std::reference_wrapper<T>> и T* заключается в том, что при T* вам нужно подумать о том, кому принадлежит указана память.

Если функция возвращает T* вы должны знать, не ответственны ли вы за освобождение памяти или кого-то еще. Это не то, о чем вы должны беспокоиться, когда это ссылка.