Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.04 c
15-1180993364
IMHO
2007-06-05 01:42
2007.07.08
Данные на дисках обречены...


2-1181847644
Max_
2007-06-14 23:00
2007.07.08
ADOConnection


2-1181825444
Alex_C
2007-06-14 16:50
2007.07.08
Ускорение работы программы


1-1178614169
allucard
2007-05-08 12:49
2007.07.08
Обработчик события для компонента созданного в RunTime.


6-1159720721
_Anwy_
2006-10-01 20:38
2007.07.08
Авторизация на сайте с помощью IdHTTP





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский