Основные положения C ++ был представлен недавно (поздравляю!), и я обеспокоен gsl::not_null
тип. Как указано в I.12. Объявить указатель, который не должен быть нулевым, как not_null
:
Чтобы избежать разыменования ошибок nullptr. Чтобы улучшить производительность путем
избегая избыточных проверок для nullptr.…
Указав намерение в
источник, разработчики и инструменты могут обеспечить лучшую диагностику, такую как
найти некоторые классы ошибок с помощью статического анализа и выполнить
оптимизации, такие как удаление веток и нулевые тесты.
Намерение ясно. Тем не менее, у нас уже есть языковая функция для этого. Указатели, которые не могут быть нулевыми, называются ссылками. И хотя ссылки не могут быть восстановлены после их создания, эта проблема решается std::reference_wrapper
,
Основное различие между gsl::not_null
а также std::reference_wrapper
Я вижу в том, что последний может использоваться только вместо указателей, в то время как первый работает на что угодно nullptr
присваивается (цитата из F.17: используйте not_null, чтобы указать, что «null» не является допустимым значением):
not_null
не только для встроенных указателей. Это работает для
array_view
,string_view
,unique_ptr
,shared_ptr
, и другие
указатели типа.
Я представляю таблицу сравнения функций, как показано ниже:
T&
:
nullptr
? — даstd::reference_wrapper<T>
:
nullptr
? — даgsl::not_null<T*>
:
nullptr
? — даТеперь вот вопросы, наконец:
std::reference_wrapper
сейчас бесполезно?PS Я создал теги cpp-core-guidelines
а также guideline-support-library
на это я надеюсь правильно.
Рекомендации не указатели, которые не могут быть нулевыми. Ссылки семантически сильно отличаются от указателей.
Рекомендации имеют значение семантика присваивания и сравнения; то есть операции присваивания или сравнения, включающие ссылки, читают и пишут значение. Указатели есть (нелогично) ссылка семантика присваивания и сравнения; то есть операции присваивания или сравнения, включающие указатели чтения и записи ссылка сам (то есть адрес объекта, на который ссылаются).
Как вы заметили, ссылки не могут быть восстановлены (из-за их семантики присваивания значения), но reference_wrapper<T>
шаблон класса Можно быть отскок, потому что он имеет ссылка семантика присваивания. Это потому что reference_wrapper<T>
разработан для использования с контейнерами и алгоритмами STL и не будет работать правильно, если его оператор присваивания копии не делает то же самое, что и конструктор копирования. Тем не мение, reference_wrapper<T>
по-прежнему имеет значение сравнение семантика, как ссылка, поэтому она ведет себя очень по-разному по отношению к указателям при использовании с контейнерами и алгоритмами STL. Например, set<T*>
может содержать указатели на разные объекты с одинаковым значением, в то время как set<reference_wrapper<T>>
может содержать ссылку только на один объект с заданным значением.
not_null<T*>
шаблон класса имеет присвоение ссылки а также семантика сравнения, как указатель; это указатель типа. Это означает, что он работает как указатель при использовании с контейнерами и алгоритмами STL. Это просто не может быть нулевым.
Таким образом, вы правы в своей оценке, за исключением того, что вы забыли о семантике сравнения. И нет, reference_wrapper<T>
не будет устаревшим ни в каком виде типа указателя, потому что он имеет семантику сравнения значений в виде ссылки.
Я думаю, что есть еще варианты использования для std::reference_wrapper
которые не покрыты gsl::not_null
, В принципе, std::reference_wrapper
отражает ссылку и имеет operator T&
преобразование, в то время как not_null
имеет интерфейс указателя с operator->
, Один случай использования, который сразу приходит мне в голову, — это создание потока:
void funcWithReference(int& x) { x = 42; }
int i=0;
auto t = std::thread( funcWithReference, std::ref(i) );
Если я не могу контролировать funcWithReference
Я не могу использовать not_null
,
То же самое относится к функторам для алгоритмов, и мне пришлось использовать его для связывания boost::signals
тоже.