![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Здравствуйте.
Столкнулся с некоторыми проблемами при создании объекта и массива этого-же объекта, конкретно - с манипуляцией элементов в массиве. Объект содержит только энный набор данных и несколько функций "одиночной" обработки. Код:
type
TCommand = class (TObject)
ComList: TStringList;
Error: Cardinal;
public
procedure AssignObjects (ObjArray: array of TObject) ;
procedure AssignStrings (Str: TStrings);
procedure AssignObjectsStrings (Str: TStrings);
constructor Create;
destructor Free;
end;Код:
TCommandStackElement= record
Command: TCommand;
Time: TDateTime;
end;
TCommandStackElmt = array of TCommandStackElement;
PCommandStackElmt = ^TCommandStackElmt;
TCommandStack = class (TObject)
private
PCommandStack: PCommandStackElmt;
Created: Boolean; //проверка на "созданность"
FSize: Cardinal; //под сколько элементов уже выделено памяти
FCount: Cardinal; //количество занятых элементов
public
function AddNew (ICommand: TCommand): Boolean;
//и остальные функции обработкиКод:
ReallocMem(PCommandStack,(FSize)*SizeOf(TCommandStackElement)); 2я проблема в добавлении элемента - для этого вызывается AddNew (ICommand: TCommand): Код:
function TCommandStack.AddNew (ICommand: TCommand): Boolean;
var OldLength: Cardinal;
begin
try
Result:=True;
if FSetSize(Self.FCount+1) then
begin
Inc(FCount);
try
PCommandStack^[Self.FCount].Time:=Now;
PCommandStack^[Self.FCount].@Command:=@ICommand;
except
Result:=False;
PCommandStack^[Self.FCount].Command:= TCommand.create;
PCommandStack^[Self.FCount].Command:=ICommand;
end;
end;
except
end;
end;Код:
PCommandStackElement = ^TCommandStackElement;
TCommandStackElmt = array of ^PCommandStackElement;
PCommandStackElmt = ^TCommandStackElmt;
TCommandStack = class (TObject)
private
PCommandStack: PCommandStackElmt;Последний раз редактировалось Velz, 02.04.2012 в 16:19. |
|
#2
|
|||
|
|||
|
Если собрались использовать array of TCommandStackElement, то надо так
PCommandStackElmt = ^TCommandStackElmt; - выкинуть. Код:
TCommandStack = class (TObject)
private
PCommandStack: TCommandStackElmt;//<<==-- здесь так
Created: Boolean; //проверка на "созданность"
FSize: Cardinal; //под сколько элементов уже выделено памяти
FCount: Cardinal; //количество занятых элементоввместо Код:
ReallocMem(PCommandStack,(FSize)*SizeOf(TCommandStackElement)); Код:
SetLength(PCommandStack,FSize); Убрать ^ при обращении к PCommandStack. и что Вы хотели сделать здесь Код:
PCommandStack[Self.FCount].@Command:=@ICommand;Код:
PCommandStack[Self.FCount].Command:=TCommand.create; // сначала записываем в поле указатель на только что созданный класс PCommandStack[Self.FCount].Command:=ICommand; // а затем затираем его Если Вы вот этим кодом @Command:=@ICommand; хотите побайтно скопировать содержимое объекта TCommand - то хочу разочаровать - ничего не выйдет. И немножко ликбеза. Экземпляры классов в дельфи - всегда указатели. Копирующего конструктора и поэлементного присваивания по умолчанию для классов НЕТ !. Если они нужны - нужно делать самому. Для некоторых классов копирование содержимого имеется(например TStringList, TBitmap), но у этих классов есть метод Assign, в котором прописано - что и как копируется/присваивается. Удачи. |
| Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
Velz (03.04.2012)
| ||
|
#3
|
|||
|
|||
|
К сожалению, использовать SetLength не выходит - установка таким образом длинны массива происходит только 1 раз, потом не меняет (не знаю с чем это связанно), поэтому и пришлось переходить на указатели и использовать выделение памяти. Поэтому в данном случае от PCommandStackElmt = ^TCommandStackElmt; избавиться не удается =(
Код:
PCommandStack[Self.FCount].Command:=TCommand.create; // сначала записываем в поле указатель на только что созданный класс PCommandStack[Self.FCount].Command:=ICommand; // а затем затираем его Код:
PCommandStack[Self.FCount].@Command:=@ICommand; Таким образом, остался только вопрос с "безопасной" работой памяти в ReallocMem (ибо избавиться от него не удается). Пытался сделать конструкцию с GetMemory и дополнительным указателем, с последующим копированием данных и переприсвоением указателя: Код:
GetMem(RecPnt,(BufSize)*SizeOf(TCommandStackElement)); if PCommandStack<>nil then begin Move(PCommandStack^,RecPnt^,SizeOf(TCommandStack)); FreeMem(PCommandStack, FSize * SizeOf(TCommandStack)); end; PCommandStack := RecPnt; |
|
#4
|
|||
|
|||
|
>установка таким образом длинны массива происходит только 1 раз
Что значит не меняет, - это как Вы делаете? А если хотите работать через GetMem, RealocMem, FreeMem? то нельзя использовать динамический массив (array of) >нужно будет массив указателей А как я уже говорил в Дельфи экземпляры классов итак указатели. |
| Этот пользователь сказал Спасибо icWasya за это полезное сообщение: | ||
Velz (03.04.2012)
| ||
|
#5
|
|||
|
|||
|
Цитата:
Цитата:
Последний раз редактировалось Velz, 03.04.2012 в 09:59. |
|
#6
|
|||
|
|||
|
вот это PCommandStack[Self.FCount].@Command вообще не должно скомпилироваться,
А вот это PCommandStack[Self.FCount].Command:=ICommand; PCommandStack[Self.FCount].Command:=@ICommand; одно и то же. И ещё раз: если работаете с GetMem, ReallocMem, FreeMem, то нельзя использовать динамический массив. Надо тогда делать так TCommandStackElmt = array[0 .. MaxInt div 4-1] of TCommandStackElement; PCommandStackElmt = ^TCommandStackElmt; и не использовать SetLength никогда |
|
#7
|
|||
|
|||
|
Цитата:
GetMem, ReallocMem, FreeMem и SetLength использовал только в различных типах данных (1е с указателем на массив, 2е при работе непосредственно с массивом). Вопрос: TCommandStackElmt = array[0 .. MaxInt div 4-1] of TCommandStackElement; это фиксированный массив по константе? Если да, то возможно ли сделать динамический массив из PCommandStackElmt? Или вообще сделать динамический массив указателей: Код:
TCommandStackElmt = ^TCommandStackElement; PCommandStackElmt = array of TCommandStackElmt; |
|
#8
|
|||
|
|||
|
я же говорю
TCommandStackElmt = array[0 .. MaxInt div 4-1] of TCommandStackElement; PCommandStackElmt = ^TCommandStackElmt; Размер указан толькол для обмана компилятора - что бы не ругался на границу массива. Вы же нигде не будете использовать переменные типа TCommandStackElmt.( я надеюсь ![]() а работать так Код:
PCommandStack : PCommandStackElmt; GetMem(PCommandStack , FCount*sizeof(TCommandStackElement)); ReallocMem(PCommandStack , FCount*sizeof(TCommandStackElement)); FreeMem(PCommandStack); Ещё раз для тех кто в танке если написали Код:
PCommandStackElmt = array of TCommandStackElmt ![]() |
|
#9
|
|||
|
|||
|
ObjectList из модуля Contnrs и никаких проблем
только надо свойство OwnsObjects иметь ввиду, если не надо, чтобы он сам освобождал элементы, при их удалении я бы сделал так: PHP код:
|
|
#10
|
|||
|
|||
|
Цитата:
Уххх... в общем получилось все сделать Итоговая конструкция осталась изначальной: Код:
TCommandStackElmt = array of TCommandStackElement; PCommandStackElmt = ^TCommandStackElmt; Увеличение массива происходит через SetLength(PACommandStack^,FCount); присвоение данных через PACommandStack^[FCount-1].Command:=ICommand; так-же без проблем. А косяк обнаружился в теле основной программы - после выполнения AddNew (ICommand: TCommand), технично вызывался деструктор того, что уходило в ICommand... В общем весь косяк был в том, что я изначально не знал о "указательной" природе классов, и удалял тот-же самый элемент, который только только забил в массив. P.S. Называется хотел как лучше (раз создал объект - будь добр в конце удалить, дабы не мешался в памяти), а получилось через ... Спасибо ![]() |
|
#11
|
|||
|
|||
|
Ну так вернёмся к моему первому ответу - если SetLength заработал, тогда
вот это PCommandStackElmt = ^TCommandStackElmt; - не нужно. используй прямо Код:
PCommandStack : TCommandStackElmt; |
|
#12
|
|||
|
|||
|
Цитата:
Код:
TCommandStack = class (TObject)
private
Created: Boolean;
FSize: Cardinal;
FCount: Cardinal;
function GetLength : Cardinal;
function FSetSize (NewSize: Cardinal) : Boolean;
procedure FSetCount (NewCount: Cardinal);
public
CommandStack: array of TCommandStackElement;P.S. Деструктор все-равно делать, вот только в какой момент и к кому его прикручивать... но это уже другая тема =) Последний раз редактировалось Velz, 03.04.2012 в 17:01. |