Форум: "Основная";
Текущий архив: 2007.07.08;
Скачать: [xml.tar.bz2];
Вниз
Зависание программы при выходе из метода моего класса Найти похожие ветки
← →
logslava (2007-05-09 14:15) [0]Всех с праздником Победы!
Пишу класс, который выдает в случайном порядке числа от 1 до задаваемого MaxValue. В массиве UsedValues храню те цифры, которые уже были выданы, и при выдаче нового проверяю, чтобы не повторялись выдаваемые значения. В коде ниже оставил самые основные методы. Ошибка почему-то возникает при выходе из процедуры GetNextValue;
Сам класс (урезанный)
type
TRandomer = class
constructor Create(lMaxValue: Integer);
private
MaxValue: Integer;
UsedValues: array of Integer;
function ValueIsUsed(Value: Integer): Boolean;
procedure ResetUsedValues;
public
function GetNextValue: Integer;
end;
implementation
uses Math;
constructor TRandomer.Create(lMaxValue: Integer);
begin
inherited Create;
Self.MaxValue := lMaxValue;
Randomize;
// инициализация массива UsedValues
SetLength(UsedValues, MaxValue);
ResetUsedValues;
end;
function TRandomer.ValueIsUsed(Value: Integer): Boolean;
var i: Integer;
begin
Result := False;
for i:=1 to MaxValue do begin
if UsedValues[i] = Value then begin
Result := True;
Break;
end;
end;
end;
procedure TRandomer.ResetUsedValues;
var i: Integer;
begin
for i:=1 to MaxValue do begin
UsedValues[i] := 0;
end;
end;
function TRandomer.GetNextValue: Integer;
var Res: Integer; // переменная для формирования результата
Iteration: Integer; // сигн. метка выхода из цикла - отражает количество уже отработанных чисел
begin
Iteration := 0;
repeat
Res := RandomRange(1, MaxValue);
Inc(Iteration);
until {будет найдено не использ значение или будут пересмотрены все значения}
(not ValueIsUsed(Res))or(Iteration=MaxValue);
Result := Res;
end;
end.
Вызывающий код
var Randomer: TRandomer;
testInt: Integer;
...
Randomer := TRandomer.Create(10);
testInt := Randomer.GetNextValue;
ShowMessage(IntToStr(testInt)); // сюда даже не приходит, зависает на выходе из предыдущей процедуры
Подскажите, пожалста, в чем моя ошибка?
← →
{RASkov} © (2007-05-09 14:26) [1]> [0] logslava (09.05.07 14:15)
> for i:=1 to MaxValue do begin
if UsedValues[i] = ....
Вот она ошибка...
SetLength(UsedValues, MaxValue);
установит нижнюю границу в 0.., ну а верхнюю сам понимаешь в MaxValue-1.
Т.е. у тебя в цикле просматриваются столько же элементов сколько и их всего в массиве, но индекс идет с +1 к текущему.
← →
{RASkov} © (2007-05-09 14:27) [2]> Т.е. у тебя в цикле просматриваются столько же элементов сколько и их всего в массиве, но индекс идет с +1 к текущему.
Криво сказал, но думаю суть понята.... :)
← →
logslava (2007-05-09 14:47) [3]Конечно! Глупая ошибка! Спасибо огромное, еще раз с празником!
← →
default © (2007-05-09 15:07) [4]у тебя очень неэффективный алгоритм
делают обычно так
есть, например, массив чисел 1..N(массив нумеруется тут с единицы)
выбирается первое число через Random(N)+1(это позиция выбираемого числа в массива)
после этого это первое число меняется местами с последним
второе число гененируется как Randim(N-1)+1
далее меняется это второе число местами с предпоследним
третье число генерируется как Random(N-2)+1
потом меняется местами оно с предпредпоследним
и тд
← →
Rial © (2007-05-09 15:27) [5]1. > Self.MaxValue := lMaxValue;
Опасный момент...
2. > for i:=1 to MaxValue do begin
заменить на
for i:=0 to MaxValue - 1 do begin
3. Вызов Randomize в конструкторе класса
вообще можно считать ошибкой в данном случае.
А если такой класс будет не один ?!
4. В методе GetNextValue есть лишняя переменная.
5. Что будешь делать, когда не будет хватать
размеров массива ?
6.
> for i:=1 to MaxValue do begin
> UsedValues[i] := 0;
> end;
Лучше используй ZeroMemory() .
7. А почему конструктор не в public ?
← →
{RASkov} © (2007-05-09 17:17) [6]> [5] Rial © (09.05.07 15:27)
> 1. > Self.MaxValue := lMaxValue;
> Опасный момент...
Нисколько.... Self все равно неявно подставиться.
> 7. А почему конструктор не в public ?
конструктор published. Будет доступен...., но у меня впринципе тот же вопрос ;)
> 3. Вызов Randomize в конструкторе класса
> вообще можно считать ошибкой в данном случае.
> А если такой класс будет не один ?!
А что страшного может произойти?
← →
Rial © (2007-05-09 17:35) [7]1.
> [6] {RASkov} © (09.05.07 17:17)
> Нисколько.... Self все равно неявно подставиться.
Просто с таких мелочей начинаются другие
подобные ошибки. Которые уже действительно ошибки,
а не опасные места.
Например что то вроде этого:
Var
Form1 : TForm1;
constructor TForm1.Create;
begin
...
Form1.Width:=200;
end;
2.
> А что страшного может произойти?
Генератор случаных чисел нужно инициализировать
один раз за время выполнения программы.
А иначе- последтсвия нетрудно проверить самому.
← →
{RASkov} © (2007-05-09 17:45) [8]> [7] Rial © (09.05.07 17:35)
> Var
> Form1 : TForm1;
> constructor TForm1.Create;
> begin
> ...
> Form1.Width:=200;
> end;
Вот здесь согласен...
> Генератор случаных чисел нужно инициализировать
> один раз за время выполнения программы.
> А иначе- последтсвия нетрудно проверить самому.
Вот, чесслово расскажи, что может быть плохого... Нет, я не придираюсь, хочу узнать, так как криминала, с этим связанного, не наблюдал..
Вообще, как говориться - достаточно - одного раза вызывать в программе, но ни как не про ограничение кол-во раз вызовов.
← →
{RASkov} © (2007-05-09 17:48) [9]> Просто с таких мелочей начинаются другие
> подобные ошибки. Которые уже действительно ошибки,
> а не опасные места.
Ошибки, в данном случае, нет.... все зависит от программера и его алгоритма программы, а вот тон/стиль программирования - плохой.
← →
Rial © (2007-05-09 17:54) [10]> [8] {RASkov} © (09.05.07 17:45)
Извини, в данным случае я могу быть и не прав.
Были как то пару раз глюки, связанные
с многочисленной инициализацией.
Сейчас проверил - их нет. Если смогу восстановить
ситуацию полностью - покажу пример. :)
Просто лучше порой перестраховаться.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2007.07.08;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.046 c