Динамический массив - проблема с указателями
От: Lenok-Sim  
Дата: 20.09.05 11:05
Оценка:
Здравствуйте

При работе с динамическими массивами я столкнулась с такой неприятной проблемой:

PMyType = ^TMyType
TMyType = record
...
end;

var
  MyArray: array of TMyType
  MyArrayLength: integer = 0;

function Add: PMyType;
begin
  MyArrayLength := MyArrayLength + 1;
  SetLength(MyArray, MyArrayLength);
  result := @MyArray[MyArrayLength-1];
end;

procedure ShowPointerList;
var
  i: integer;
begin
  ListBox1.Clear;
  for i := 0 to MyArrayLength - 1 do
    ListBox1.Items.Add(IntToHex(Integer(@MyArray[i]), 8));
end;


При последовательном добавлении элементов (функция Add) все в порядке до тех пор, пока элементов не станет больше 8-ми. После этого все указатели меняются каждый раз при добавлении где-то до 40..50 элементов, потом все успокаивается.

После переделки на array of PMyType все заработало, однако вопрос все равно остается без ответа — что происходит с указателями при добавлении элементов?

Заранее благодарю за ответ.
Симонова Елена
Re: Динамический массив - проблема с указателями
От: LennaBMP  
Дата: 20.09.05 12:21
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

LS>При последовательном добавлении элементов (функция Add) все в порядке до тех пор, пока элементов не станет больше 8-ми. После этого все указатели меняются каждый раз при добавлении где-то до 40..50 элементов, потом все успокаивается.


Указатели на что меняются при добавлении элемента?
Вообще, приходилось сталкиваться с динамическими массивами — это такая sorry зараза...
посмотри
Автор: LennaBMP
Дата: 16.09.05

Понятно одно — указателями на динамический массив лучше не пользоваться.
Re: Динамический массив - проблема с указателями
От: Dimonka Верблюд  
Дата: 20.09.05 12:39
Оценка: 1 (1)
Здравствуйте, Lenok-Sim, Вы писали:

LS>При последовательном добавлении элементов (функция Add) все в порядке до тех пор, пока элементов не станет больше 8-ми. После этого все указатели меняются каждый раз при добавлении где-то до 40..50 элементов, потом все успокаивается.


LS>После переделки на array of PMyType все заработало, однако вопрос все равно остается без ответа — что происходит с указателями при добавлении элементов?


Уважаемая Елена, при добавлении нового элемента ты получаешь не указатель на элемент, а указатель на элемент в массиве. Т.к. массив динамический, то он выделяется заново при изменении его размера. Соответственно адреса элементов массива изменяются.

Вообще такой подход говорит о незнании базовых понятий в Delphi, например о существовании класса TList.
Работа со списками уже давно решена — пользуйтесь Если есть Model Maker, то создание подобного специализированного списка вообще состоит из нескольких кликов мышкой..
Re: Динамический массив - проблема с указателями
От: konst  
Дата: 20.09.05 12:40
Оценка:
Стало интересно, посмотрел, как работает... Указатели увеличиваются нормально, на одинаковую величину все, т.е. массив ведёт себя как массив совершенно по сишному. Что именно не получалось то? Смотрел в таком виде:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
PMyType = ^TMyType;
TMyType = record
  a: Integer;
  b: Currency;
end;

var
  MyArray: array of TMyType;
  MyArrayLength: integer = 0;

function Add: PMyType;
begin
  MyArrayLength := MyArrayLength + 1;
  SetLength(MyArray, MyArrayLength);
  result := @MyArray[MyArrayLength-1];
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
begin
  for i := 0 to 45 do
    Add;
  ListBox1.Clear;
  for i := 0 to MyArrayLength - 1 do
    ListBox1.Items.Add(IntToHex(Integer(@MyArray[i]), 8));
end;

end.


Форма с листбоксом и кнопкой:
object Form1: TForm1
  Left = 210
  Top = 301
  Width = 870
  Height = 640
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object ListBox1: TListBox
    Left = 8
    Top = 16
    Width = 329
    Height = 337
    ItemHeight = 13
    TabOrder = 0
  end
  object Button1: TButton
    Left = 208
    Top = 368
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
end
Re[2]: Динамический массив - проблема с указателями
От: Lenok-Sim  
Дата: 20.09.05 13:09
Оценка: +1
Здравствуйте, konst, Вы писали:

K>Стало интересно, посмотрел, как работает... Указатели увеличиваются нормально, на одинаковую величину все, т.е. массив ведёт себя как массив совершенно по сишному. Что именно не получалось то? Смотрел в таком виде:


В таком виде (проект из одной формы, листбокса и кнопочки) все отлично работает.
В другом случае, когда есть проект со многими формами и т.д. смещаются адреса элементов, то есть указатели на запись.

Я уже писала, что с Array of PMyType все работает как и должно:


MyArray: array of PMyType;
...

GetMem(MyArrayt[i], SizeOf(PMyType));
...

ListBox1.Items.Add(IntToHex(Integer(MyArray[i]), 8));


По здравому размышлению я пришла к выводу, что так и должно быть — если массив перестает помещаться в куске свободной непрерывной памяти, то его переносят в другой кусок, поэтому и меняются указатели.
Re[2]: Динамический массив - проблема с указателями
От: Lenok-Sim  
Дата: 20.09.05 13:31
Оценка:
Здравствуйте, Dimonka, Вы писали:

D>Уважаемая Елена, при добавлении нового элемента ты получаешь не указатель на элемент, а указатель на элемент в массиве. Т.к. массив динамический, то он выделяется заново при изменении его размера. Соответственно адреса элементов массива изменяются.


Спасибо, я это уже поняла. Однако "Указатель на элемент" и "указатель на элемент в массиве" — несколько одинаковые вещи, как мне кажется. "Элемент" должен принадлежать чему-то, иначе он не элемент.

D>Вообще такой подход говорит о незнании базовых понятий в Delphi, например о существовании класса TList.

О существовании TList я отлично знаю, спасибо. Несколько неудобно каждый раз заводить дополнительный класс и преобразовывать значения, которые он возвращает, к другому типу. Кроме того, лишний вызов функции Get() замедляет работу, особенно при больших количествах элементов. Статический массив еще быстрее, но в данном случае нужен именно динамический.

D>Работа со списками уже давно решена — пользуйтесь Если есть Model Maker, то создание подобного специализированного списка вообще состоит из нескольких кликов мышкой..


Интересно, сколько кликов мышкой Вам понадобится, чтобы из полученного списка заполнить IDirect3DVertexBuffer9? Каждому решению свое место, на мой взгляд

Симонова Елена
Re[2]: Динамический массив - проблема с указателями
От: Lenok-Sim  
Дата: 20.09.05 13:35
Оценка:
Здравствуйте, LennaBMP, Вы писали:

LBM>Указатели на что меняются при добавлении элемента?

Указатели на предыдущие элементы

LBM>Вообще, приходилось сталкиваться с динамическими массивами — это такая sorry зараза...

Не стоит их ругать — массив из классов работает отлично

LBM>посмотри
Автор: LennaBMP
Дата: 16.09.05

LBM>Понятно одно — указателями на динамический массив лучше не пользоваться.
Спасибо, я это уже поняла

Симонова Елена
Re[3]: Динамический массив - проблема с указателями
От: Dimonka Верблюд  
Дата: 20.09.05 14:00
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

D>>Вообще такой подход говорит о незнании базовых понятий в Delphi, например о существовании класса TList.

LS>О существовании TList я отлично знаю, спасибо. Несколько неудобно каждый раз заводить дополнительный класс и преобразовывать значения, которые он возвращает, к другому типу. Кроме того, лишний вызов функции Get() замедляет работу, особенно при больших количествах элементов. Статический массив еще быстрее, но в данном случае нужен именно динамический.

Даже не моргнув глазом скажу, что Вы не там гонитесь за скоростью . Лишний вызов Get() просто ничто, по сравнению с потерей скорости на изменениях размеров динамического массива.

D>>Работа со списками уже давно решена — пользуйтесь Если есть Model Maker, то создание подобного специализированного списка вообще состоит из нескольких кликов мышкой..


LS>Интересно, сколько кликов мышкой Вам понадобится, чтобы из полученного списка заполнить IDirect3DVertexBuffer9? Каждому решению свое место, на мой взгляд


Конечно всегда нужно искать компромис между скоростью и гибкостью архитектуры. Я предпочитаю кликать мышкой в ModelMaker-е, чем писать на ассемблере. Я так же могу в ответ спросить, а правильный ли Вы инструмент(Delphi) выбрали для решения вашей задачи?
Re[3]: Динамический массив - проблема с указателями
От: Sergei I. Gorelkin Россия  
Дата: 20.09.05 16:32
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

LS>... Кроме того, лишний вызов функции Get() замедляет работу, особенно при больших количествах элементов. Статический массив еще быстрее, но в данном случае нужен именно динамический.


Есть свойство TList.List[Index], использование которого позволяет избавиться от вызовов Get() вообще, только нужно самостоятельно следить, чтобы индекс не выходил за границы.
Re[3]: Динамический массив - проблема с указателями
От: LennaBMP  
Дата: 21.09.05 07:18
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

LS>Не стоит их ругать — массив из классов работает отлично


Никто и не спорит с этим. Экземпляры классов — это переменные, управляемые пользователем. А как насчет динамического массива переменных с автоматическим управлением памятью — интерфейсов, например? Кто-нибудь пробовал? Автоматическое управление памятью — хорошая штука, но не всегда...
Re[3]: Динамический массив - проблема с указателями
От: LennaBMP  
Дата: 21.09.05 07:27
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

LS>О существовании TList я отлично знаю, спасибо. Несколько неудобно каждый раз заводить дополнительный класс и преобразовывать значения, которые он возвращает, к другому типу. Кроме того, лишний вызов функции Get() замедляет работу, особенно при больших количествах элементов. Статический массив еще быстрее, но в данном случае нужен именно динамический.


Не сочтите за рекламу , но М.Кэнту в своей книге по D7 дал небольшую главу, посвященную контейнерам и спискам — TObjectList, TBucketList etc. В ней есть и о том, как обеспечить сохранение типа при использовании списка.
Re[3]: Динамический массив - проблема с указателями
От: Oleg A. Bachin Украина  
Дата: 21.09.05 08:00
Оценка:
Здравствуйте, Lenok-Sim, Вы писали:

LS>По здравому размышлению я пришла к выводу, что так и должно быть — если массив перестает помещаться в куске свободной непрерывной памяти, то его переносят в другой кусок, поэтому и меняются указатели.


правильно. так все и есть. поэтому в основном предпочтительнее работать например с TList.
плюс ко всему всякому, при больших объемах добавления перевыделение памяти будет меньше засчет иной стратегии.
выделение идет сразу с запасом (Capacity).
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Best regards,
Oleg A. Bachin
Re[4]: Динамический массив - проблема с указателями
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.09.05 06:46
Оценка:
Здравствуйте, LennaBMP, Вы писали:
LBM>Никто и не спорит с этим. Экземпляры классов — это переменные, управляемые пользователем. А как насчет динамического массива переменных с автоматическим управлением памятью — интерфейсов, например? Кто-нибудь пробовал? Автоматическое управление памятью — хорошая штука, но не всегда...
Все работает. Даже динамический массив динамических массивов интерфейсов со строковыми свойствами чудно работает.
... << RSDN@Home 1.1.4 stable rev. 510>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.