дин. массив в классе и переопределение операторов

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

дин. массив в классе и переопределение операторов

Сообщение AlexP » 14.05.2007 21:23:00

Здравствуйте.

Возникает ошибка, когда я для класса, в котором есть динамический массив, сделал переопределение оператора.

вот сам класс -

Код: Выделить всё
type pp=class
N:integer;
x:array of double;
procedure add(a,b:pp);
procedure clear(n1:integer);
end;

operator + (a,b:pp)r:pp;

implementation

operator + (a,b:pp)r:pp;
begin
r.add(a,b);
end;

procedure pp.add(a,b:pp);
var i:integer;
begin
clear(a.N);
for i:=0 to n-1 do
x[i]:=a.x[i]+b.x[i];
end;

procedure pp.clear(n1:integer);
begin
n:=n1;
setLength(x,n);
end;   


вот появление ошибки -

Код: Выделить всё
var a,b,r:pp;
begin
a:=pp.Create; a.clear(2);
b:=pp.Create; b.clear(2);
r:=pp.Create; r.clear(2);
r:=a+b;  //  <---- вот тут возникает ошибка 216


Это я что-то неправильно делаю, или это баг?

если в классе нединамический массив, или вместо класса используется обьект, то все в порядке.
Использую Lazarus 0.9.22 beta
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение shade » 14.05.2007 22:41:08

У тебя скорее всего обращение к nil, т.к. объекты классов все-таки надо создавать (про уничтожение тоже не забудьте...)
Попробуй
Код: Выделить всё
operator + (a,b:pp)r:pp;
begin
r := pp.Create;
r.add(a,b);
end;


PS: Вообще мне кажется, что перегрузка для классов не очень удачное решение. Может быть лучше будет заюзать интерфейсы, т.к. они умеют самоуничтожаться при обнулении счетчика ссылок..
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение AlexP » 15.05.2007 22:00:35

попробовал, работает, спасибо.

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

И еще странно, почему мой код работает в случае если вместо динамического массива в классе статический массив - x:array[0..1] of double;
То есть все работает прекрасно, если в классе нет дин. массива.

А через интерфейсы - это как, как в дельфийском юните Varcmpx? Я чего начал связываться с классами - потому что перегруженные операторы аналогичных обьектов намного медленнее работают...
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение shade » 15.05.2007 22:27:07

AlexP писал(а):Однако ж я создал экземпляр класса - результата в той процедуре, где вызывается оператор сложения

А потом оператор присваивания его затер, рассматривайте оператор как обычную функцию

AlexP писал(а):То есть все работает прекрасно, если в классе нет дин. массива.

Вам скорее всего (не)повезло, эта ошибка могла проявиться позже.

AlexP писал(а):А через интерфейсы - это как, как в дельфийском юните Varcmpx?

Это долгая история, но лучше попробуйте код приведенный ниже (думаю будет проще и быстрее)

Varcmpx? Не знаю, такого юнита, Delphi 6 его не находит.

AlexP писал(а):Я чего начал связываться с классами - потому что перегруженные операторы аналогичных обьектов намного медленнее работают

А любите ли вы const, так как люблю его я?
(А нужен ли pp.n?)
Код: Выделить всё
type
  pp=object
    x: array of double;
    procedure Add(const a, b: pp);
    procedure Clear(n1: Integer);
  end;

operator + (const a,b:pp)r:pp;
begin
  r.add(a,b);
end;

procedure pp.Add(const a, b: pp);
var
  i:integer;
  Len: integer;
begin
  Len := Length(a.x);
  clear(len);
  for i:=0 to len-1 do
    x[i]:=a.x[i]+b.x[i];
end;

procedure pp.clear(n1:integer);
begin
  setLength(x,n1);
end;

var
  a,b,r:pp;
  i: Integer;
begin
  a.clear(2);
  a.x[0] := 1;
  a.x[1] := 2;
  b.clear(2);
  b.x[0] := 3;
  b.x[1] := 4;
  r := a + b;
  for i := 0 to Length(r.x)-1 do
    writeln(r.x[i]);
end.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение shade » 15.05.2007 22:55:45

А еще лучше попробуйте так:
Код: Выделить всё
{$IFDEF DEBUG}
{$ASSERTIONS ON}
{$ENDIF}

{$IFDEF RELEASE}
{$ASSERTIONS OFF}
{$ENDIF}

type
  vector_t = array of double;

function vector(const v: array of double): vector_t;
var i: Integer;
begin
  SetLength(vector, High(v) - Low(v) + 1);
  for i := Low(v) to High(v) do vector[i] := v[i];
end;

operator + (const a, b: vector_t) Result: vector_t;
var i, Len: Integer;
begin
  Len := Length(a);
  Assert(Len = Length(b));
  SetLength(Result, Len);
  for i := 0 to Len-1 do Result[i] := a[i] + b[i];
end;

var
  r: vector_t;
  i, len: Integer;
begin
  r := vector([1, 2]) + vector([3, 4]);
  len := Length(r);
  for i := 0 to len-1 do writeln(r[i]);
end.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение AlexP » 16.05.2007 21:36:03

shade писал(а):А потом оператор присваивания его затер, рассматривайте оператор как обычную функцию


Ага, понял, теперь дошло.

shade писал(а):Varcmpx? Не знаю, такого юнита, Delphi 6 его не находит.


Немного ошибся, он называется VarCmplx, появился в 7-й версии, как иллюстрация того, что в ней можно использовать переопределение операторов.

shade писал(а):А любите ли вы const, так как люблю его я?


Уже полюбил 8)) Кстати, провел небольшое "исследование" на тему быстродействия оператора на базе вашего первого примера, простой прогонкой цикла

for i:=0 to 10000000 do r := a + b;

без const он выполняется за 12 секунд, с const - за 6.

Если пример немного переделать - не вызывать из оператора ф-ю add, а в нем поместить то, что она должна делать, т.е. вместо

Код: Выделить всё
operator + (const a,b:ss)r:ss;
begin
  r.add(a,b);
end;

procedure ss.Add(const a, b: ss);
var
  i:integer;
  Len: integer;
begin
  Len := Length(a.x);
  clear(len);
  for i:=0 to len-1 do
    x[i]:=a.x[i]+b.x[i];
end;


написать

Код: Выделить всё
operator + (const a,b:ss)r:ss;
var
  i:integer;
  Len: integer;
begin
  Len := Length(a.x);
  r.clear(len);
  for i:=0 to len-1 do
    r.x[i]:=a.x[i]+b.x[i];
end;


то этот цикл выполняется всего за 0,7 секунды - т.е. за такое же время, за какое выполняется цикл

for i:=0 to 10000000 do r.add(a,b);

ЗЫ: большое спасибо за помощь.
AlexP
новенький
 
Сообщения: 20
Зарегистрирован: 11.05.2007 19:04:01

Сообщение shade » 16.05.2007 21:55:39

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

Посмотрел, в Dephi 6 тоже есть этот юнит. Нет интерфейсы это другая тема. object + const будет быстрее, чем interface + const

Чувствую, что const (и иже с ним) можно целую статью посвятить, чтобы народ понимал, в чем фишка.
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Attid » 16.05.2007 23:49:55

Чувствую, что const (и иже с ним) можно целую статью посвятить, чтобы народ понимал, в чем фишка.

сейчас появится ev и скажет что он её уже ждет на мыло =)
уже увидел. жаль что нет тега перечеркнутый текст.
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2586
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение ev » 17.05.2007 08:10:59

сейчас появится ev и скажет что он её уже ждет на мыло =)
уже увидел. жаль что нет тега перечеркнутый текст.

пора бота запустить, чтоб на желание статьи сразу ответ постил - ждем на мыло :lol:
ev
долгожитель
 
Сообщения: 1772
Зарегистрирован: 27.04.2005 23:19:06
Откуда: Москва


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Рейтинг@Mail.ru