Я использовал -1 в качестве значения флага для функции, тип возвращаемой которой size_t (тип без знака).
Сначала я этого не заметил, особенно потому, что это не вызывало ошибок в моем коде (я проверял это с помощью x == -1, а не x < 0).
Есть ли тонкие причины, по которым я не должен оставить все как есть? Когда это может вести себя неожиданно? Это обычно используется?
ptrdiff_t встречается реже, требует больше времени для ввода, и в любом случае это не совсем подходящий тип, поскольку функция возвращает индекс в массив.
-1
будет всегда преобразовывать в максимальное значение без знака, это связано с разделом 4.7
Интегральные преобразования:
Если тип назначения не имеет знака, полученное значение является наименее целым числом без знака, конгруэнтным источнику
целое число (по модулю 2n, где n — количество бит, используемых для представления типа без знака). [Примечание: в двух
дополняющее представление, это преобразование является концептуальным и нет изменений в битовой структуре (если есть
нет усечения). —Конечная записка]
Та же цитата для C99 будет из 6.3.1.3
:
В противном случае, если новый тип без знака, значение преобразуется путем многократного добавления или
вычитание больше, чем максимальное значение, которое может быть представлено в новом типе
пока значение не окажется в диапазоне нового типа.49)
Итак, мы заканчиваем с:
-1 + (UMAX + 1)
который:
UMAX
Очевидное предостережение заключается в случае набора элементов с размером, равным максимально возможному размеру. Возможность и практичность этого случая на практике и фактически являющаяся причиной вашей проблемы на данный момент незначительны.
Если вы посмотрите на C ++ std::string
класс, вы заметите static std::string::npos
элемент данных определяется как точно -1
конвертировано в std::string::size_type
(что на самом деле просто std::size_t
, Это дает этой «технике» чувство приоритета, что позволяет ей полностью реализовать Принцип Наименьшего Сюрприза ™, который всегда является Доброй вещью®.
Теперь, используя -1
прямо в сравнении, как это напрашивается на неприятности. Вы должны, как в std::string
В этом случае убедитесь, что для этого значения есть доступное имя, которое обеспечит его особое значение. к сожалению, система типов C ++ не является достаточно строгой для того, чтобы пользователь не мог выстрелить себе в ногу, но, по крайней мере, пользователь, придерживающийся документированной передовой практики, не будет думать о том, чтобы действовать иначе.
Попытавшись придумать, как это может пойти не так, я понял, что существует опасность того, что вызывающая функция может неявно преобразовать возвращаемое значение в больший тип (то есть unsigned int в unsigned long long). Затем проверяем, будет ли это значение == -1 ложным.
Более безопасный вариант — явно использовать size_t.max в качестве значения часового. Мне всегда неудобно переключаться между подписанным и неподписанным типами. Иногда я думаю, что более разумный подход — просто подписать все (как это делает Java).