Должен ли я использовать незначенные целые числа для подсчета участников?

StackOverflow https://stackoverflow.com/questions/797484

  •  18-09-2019
  •  | 
  •  

Вопрос

Должен ли я использовать без подписных целых чисел для своих членов класса Count?

Отвечать

Например, предположим, что класс

TList <T> = class
private
  FCount : Cardinal;
public
  property Count : Cardinal read FCount;
end;

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

Теперь итерация над списком выглядит так:

for I := 0 to List.Count - 1 do
  Writeln (List [I]);

Когда количество элементов, хранящихся в списке, равно нулю, компилятор пытается оценить

List.Count - 1

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

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

С этого момента я буду использовать простые целые числа для всех моих членов подсчета, чтобы избежать подобных ситуаций.

Если это полная чепуха, пожалуйста, укажите это мне :)

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

Это было полезно?

Решение

Нет, определенно нет. Delphi Idiom - это использовать целые числа здесь. Не борись с языком. В 32 -битной среде у вас не будет больше элементов в списке, за исключением случаев, когда вы попытаетесь построить растровый карту.

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

Другие советы

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

Возьмите C/C ++, например: size_t тип целого числа для размеров памяти и распределения, и не знаком, но ptrdiff_t Является ли тип для смещения, который вы получаете, когда вы вычитаете один указатель из другого, и обязательно подписан. Хотите знать, сколько элементов вы выделили в массиве? Возможно, вы вычтете first адрес элемента из last+1 Адрес элемента и раздел sizeof(element-type)? Что ж, теперь вы только что смешанные подписанные и бессознанные целые числа.

Что касается вашего заявления, что «Я думаю, что в целом это хороший принцип, чтобы всегда использовать наименее общий (эрго наиболее особенный) возможный тип». - На самом деле я думаю, что это хороший принцип для использования типа данных, который вызовет у вас наименее страх и неприятности.

Как правило, для меня это подписанный int с тех пор:

  1. У меня обычно нет списков с 231 или больше элементов в них.
  2. У вас не должно быть так больших списков :-)
  3. Мне не нравится хлопот в особых случаях в моем коде.

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

Не.

Это не просто против идиомы программирования, это явная просьба для компилятора использовать без знака арифметики, это либо склонно к аномальному поведению (если вы не защищаете от переполнения), либо неактуальные исключения для выполнения (если вы охраняете от переполнений. Временное переполнение будет фатальным, FI, когда вы вычитаете перед добавлением, даже если конечный результат является положительным, и я имею в виду заказ операций на уровне ОПК-кода, что может не иметь тривиального отношения к тому, что у вас есть в вашем код).

Имейте в виду "без подписи" делает нет Перевод на «положительный», это переводится как «нет знака», что отличается. Термин «Unsigned» был выбран по уважительной причине (и назвал его «кардинал» в Delphi, был плохим выбором IMO).

Неподписанные типы предназначены для необработанных спецификаций хранения, битвы, кода ASM, встроенных контроллеров и других специальных применений. Когда вы занимаетесь программированием высокого уровня, вы должны забыть, что вы когда-нибудь слышали о безрецептурных типах.

Мораль: Используйте итераторы и foreach Когда вы можете, потому что это вообще избегает этого вопроса.

Граничные условия часто представляют проблемы. Разрешение на тип, который может быть отрицательным, может просто изменить проблему. Возможно, это сдвигает это так, что это легче отладить, возможно, нет. Я начал использовать целые числа для подсчета таких циклов, но позже переключился на кардиналы, чтобы помочь мне поймать ошибки.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top