ВУЗ:
Составители:
Рубрика:
30
WriteLn('v4 after v4.Subtract(v1): '+v4.AsString);
p:=v2.ScalarProduct(v4);
WriteLn('v2.ScalarProduct(v4): '+p.AsString);
p.Destroy; r.Destroy;
v1.Destroy; v2.Destroy; v3.Destroy; v4.Destroy;
ReadLn;
end.
Увы, хотя компиляция и проходит успешно, выполнение програм -
мы завершается крахом в момент вызова деструктора объекта v1. Если
закомментировать строку, где производится удаление векторов , то мож-
но заметить, что первый же вывод на экран содержимого вектора v1 дает
совсем не тот результат, который ожидается. Вместо набора (1/2, 2/3, 3/4,
4/5, 5/6) мы получаем вектор , все компоненты которого равны 6/7.
Для объяснения этого факта необходимо вспомнить, что явны е
соз дание и удаление — не единственные проблемы, связанные с тем , что
объект ные переменные являются указателями. Операторы присваивания
и сравнения на равенство, применяемые к таким переменным, манипул и-
руют не самими объектами, а их адресами. Это поведение принципиал ьно
отличается от операций над записями, с которыми мы имели дело ранее.
В нашем конкретном случае проблема вызвана методом SetComp,
производящим простое совмещение адресов . В результате после выпол -
нения цикла в начале демонстрационной прог раммы все компоненты
векторов v 1 и v 2 ссылаются на один и тот же реальный объект, адресуе-
мый еще и переменной r . Поля этого объекта на последней итерации
цикла получают значения 6 и 7, чем и объясняется наблюдаемый вывод
на экран. Наконец , при удалении вектора v1 деструктор пытается не-
сколько раз (по числу компонент) удалить данный объект, что, естес т -
венно, приводит к возбуждению исключения.
Для начала попытаемся исправить ситуацию, слегка модифиц и-
ровав демонстрационную программу. Заменим строки в ее начале
v1:=RVector.Create; v2:=RVector.Create; r:=Rational.Create;
for i:=1 to Dim do begin
r.SetNum(i); r.SetDen(i+1); v1.SetComp(i, r);
r.SetNum(i+1); r.SetDen(i+2); v2.SetComp(i, r);
end;
на
v1:=RVector.Create; v2:=RVector.Create;
for i:=1 to Dim do begin
r:=Rational.Create; r.SetNum(i); r.SetDen(i+1); v1.SetComp(i, r);
r:=Rational.Create; r.SetNum(i+1); r.SetDen(i+2); v2.SetComp(i, r);
end;
WriteLn('v4 after v4.Subtract(v1): '+v4.AsString);
p:=v2.ScalarProduct(v4);
WriteLn('v2.ScalarProduct(v4): '+p.AsString);
p.Destroy; r.Destroy;
v1.Destroy; v2.Destroy; v3.Destroy; v4.Destroy;
ReadLn;
end.
Ув ы , хотя ком пил яц ия и проход ит ус пешно, в ы пол нение програм -
м ы з ав ершает с я крахом в м ом ент в ы з ов а д ес т руктора объект а v1. Е с л и
з аком м ент иров ат ь с т року, гд е произ в од ит с я уд ал ение в екторов , том ож-
ноз ам ет ит ь , чтоперв ы й же в ы в од на экран с од ержим огов ектора v1 д ает
с ов с ем не тот рез ул ьт ат, кот оры й ожид ает с я. Вм ес тонабора (1/2, 2/3, 3/4,
4/5, 5/6) м ы пол учаем в ектор, в с е ком понент ы которогорав ны 6/7.
Дл я объяс нения этого факт а необход им о в с пом нит ь , что яв ны е
с оз д ание и уд ал ение — не ед инс т в енны е пробл ем ы , с в яз анны е с т ем , что
объектны е перем енны е яв л яют с я указ ат ел ям и. О ператоры прис в аив ания
и с рав нения на рав енс т в о, прим еняем ы е к т аким перем енны м , м анипул и-
руют не с ам им и объект ам и, а их ад рес ам и. Э топов ед ение принц ипиал ь но
отл ичает с яот операц ий над з апис ям и, с которы м и м ы им ел и д ел оранее.
В нашем конкрет ном с л учае пробл ем а в ы з в ана м етод ом SetComp,
произ в од ящ им прос тое с ов м ещ ение ад рес ов . В рез ул ьт ат е пос л е в ы пол -
нения ц икл а в начал е д ем онс т рац ионной програм м ы в с е ком понент ы
в екторов v1 и v2 с с ы л ают с я на од ин и тот же реал ь ны й объект, ад рес уе-
м ы й ещ е и перем енной r. Пол я этого объект а на пос л ед ней ит ерац ии
ц икл а пол учают з начения 6 и 7, чем и объяс няет с я набл юд аем ы й в ы в од
на экран. Н аконец , при уд ал ении в ектора v1 д ес т рукт ор пы т ает с я не-
с кол ь ко раз (по чис л у ком понент ) уд ал ит ь д анны й объект, что, ес т ес т -
в енно, прив од ит к в оз бужд ению ис кл ючения.
Дл я начал а попы т аем с я ис прав ит ь с ит уац ию, с л егка м од ифиц и-
ров ав д ем онс т рац ионную програм м у. Зам еним с т роки в ее начал е
v1:=RVector.Create; v2:=RVector.Create; r:=Rational.Create;
for i:=1 to Dim do begin
r.SetNum(i); r.SetDen(i+1); v1.SetComp(i, r);
r.SetNum(i+1); r.SetDen(i+2); v2.SetComp(i, r);
end;
на
v1:=RVector.Create; v2:=RVector.Create;
for i:=1 to Dim do begin
r:=Rational.Create; r.SetNum(i); r.SetDen(i+1); v1.SetComp(i, r);
r:=Rational.Create; r.SetNum(i+1); r.SetDen(i+2); v2.SetComp(i, r);
end;
30
Страницы
- « первая
- ‹ предыдущая
- …
- 28
- 29
- 30
- 31
- 32
- …
- следующая ›
- последняя »
