Почему std :: ssize () введен в C ++ 20?

100

C ++ 20 представил std::ssize()бесплатную функцию, как показано ниже:

template <class C>
    constexpr auto ssize(const C& c)
        -> std::common_type_t<std::ptrdiff_t,
                              std::make_signed_t<decltype(c.size())>>;

Возможная реализация, похоже, использует static_castдля преобразования возвращаемого значения функции- size()члена cl ass C в ее подписанный аналог.

Поскольку size()функция-член C всегда возвращает неотрицательные значения, зачем кому-то хранить их в переменных со знаком? Если кто-то действительно хочет, это очень просто static_cast.

Почему std::ssize()введен в C ++ 20?

Джон З. Ли
источник
4
@ Jarod42 Разве это не реализация, а не undefined? (подписанное переполнение не определено. но подписанное преобразование определяется реализацией)
фон
8
Если только они еще и ssizeofоператора добавляют .
geza
3
Это может быть несколько связано: stackoverflow.com/questions/30395205/…
Marco13
10
@ JohnZ.Li Рискуя показаться слишком неконструктивным: я думаю, что вся система типов C ++ в отношении целочисленных типов нарушена. Конечно, можно утверждать, что некоторые причуды (например, незнание того, сколько бит charимеет a ) унаследованы от C и, по крайней мере, несколько смягчены (u)intX_t, но это все еще бесконечный источник столь же тонких и критических ошибок. Такие вещи, как ssizeпросто исправления, и потребуется некоторое время (возможно, «навсегда»), пока они не войдут в общие «руководства по передовым методам», которым люди (могут) неукоснительно следовать.
Marco13
6
@ Marco13: С другой стороны, система типов C / C ++ (в отличие, например, от системы фиксированных типов Java), помимо того, что позволяет коду C / C ++ работать на архитектурах, где большинство других языков не работает, позволяет компетентным инструкторам получить некоторые важные уроки в голову студента. Мол, не весь мир 64-битный. И нет, не во всем мире используются 8-битные символы. С этими вещами очень легко справиться, и это сделает вас лучшим разработчиком, если только инструкторы будут учить этому с самого начала . (И, просто чтобы убедиться, вы действительно знаете , что (u)intX_tтипы необязательно , не так ли?)
DevSolar

Ответы:

69

Обоснование описано в этой статье . Цитата:

Когда span был принят в C ++ 17, он использовал целое число со знаком как в качестве индекса, так и в качестве размера. Частично это было сделано для того, чтобы разрешить использование «-1» в качестве контрольного значения для указания типа, размер которого не был известен во время компиляции. Но наличие контейнера STL, функция size () которого возвращала значение со знаком, было проблематичным, поэтому был введен P1089, чтобы «исправить» проблему. Он получил поддержку большинства, но не получил маржу 2 к 1, необходимую для достижения консенсуса.

Этот документ, P1227, был предложением о добавлении функций std :: ssize и member ssize (), не являющихся членами. Включение их сделало бы определенный код намного более простым и позволило бы избежать нежелательных беззнаковых вычислений размера. Идея заключалась в том, что сопротивление P1089 уменьшится, если ssize () будет доступен для всех контейнеров как через std :: ssize (), так и как функции-члены.

Надав Хар'Эль
источник
31
for(int i = 0; i < container.ssize() - 1; ++i)Пример также довольно убедительный
Caleth
7
@John мне действительно кажется, что они могут делать то же самое, что и string :: npos, и просто использовать size_t (-1) в качестве специального значения.
rubenvb
15
@ JohnZ.Li Беззнаковые типы размеров STL долгое время считались ошибкой. Теперь, к сожалению, уже поздно его реформировать. Предоставление бесплатной функции - лучшее, что мы можем сделать на данный момент.
LF
16
@LF: Это был Херб Саттер на конференции (возможно, Бьярн тоже это сказал). Но он немного ошибается. Теперь, с 32-битными / 64-битными компьютерами, подписанный размер был бы лучше (так что он прав). Но в старые времена (16-битные размеры) размер со знаком был бы плохим (например, мы могли бы выделить только массивы по 32 КБ).
geza
11
@LF: Я обнаружил, что Херб упоминает это: youtube.com/watch?v=Puio5dly9N8&t=2667 . Когда он говорит, что «не очень часто встречается на практике», это верно в настоящее время. Но это было совсем не так> 20 лет назад (16-битные системы). Таким образом, использование unsigned не было большой ошибкой при проектировании STL.
geza
50

Незаконно украдено у Эрика Ниблера:

'Unsigned types signal that a negative index/size is not sane'было преобладающим мнением, когда впервые была разработана STL. Но логически подсчет вещей не обязательно должен быть положительным. Я могу вести счет в виде целого числа со знаком, чтобы обозначать количество элементов, добавленных в коллекцию или удаленных из нее. Тогда я бы хотел совместить это с размером коллекции. Если размер коллекции беззнаковый, теперь я вынужден смешивать арифметику со знаком и без знака, что является фермой ошибок. Компиляторы предупреждают об этом, но поскольку дизайн STL в значительной степени вынуждает программистов попадать в такую ​​ситуацию, предупреждение настолько распространено, что большинство людей отключают его. Это позор, потому что это скрывает настоящие ошибки.

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

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

sp2danny
источник
6
Swift использует этот подход, хотя он не беспокоится о том, что отрицательные числа со знаком переинтерпретируются как массивные беззнаковые числа (поскольку здесь нет неявных приведений, которые действительно вводят вас в этот сумасшедший дом веселья). Они просто используют подход, согласно Intкоторому (размер машинного слова) должен быть типом общей валюты целых чисел, даже если имеют смысл только положительные числа (например, индексация массива). Любое отклонение от него должно быть обосновано. Приятно не беспокоиться о повсюду слепках.
Александр - Восстановить Монику
3
@ JohnZ.Li Действительно, «unsigned int считается вредным для Java»
Наюки