Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Копирование динам. массива, подозрение на ошибку 
:(
    Опции темы
Delphist
  Дата 9.1.2011, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



Вопрос: 
Будет ли корректно скопирован массив а в массив b, и не возникнет ли ситуация, что по выходу из Foo в массиве b окажутся левые данные, т.к. массив a 
локальная переменная, а b всего лишь указатель на нее?
Код

type
  PDynArrOfInt = ^TDynArrOfInt;
  TDynArrOfInt = array of Integer;

procedure TForm1.Foo(b: PDynArrOfInt);
var
  a: TDynArrOfInt;
begin

  SetLength(a, 3);
  a[0] := 1; a[1] := 2; a[2] := 3;
  b^ := a;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  b: TDynArrOfInt;
begin

  Foo(@b);
end;


Это сообщение отредактировал(а) Delphist - 9.1.2011, 13:34


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
Amphiluke
Дата 9.1.2011, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


   ☽
***


Профиль
Группа: Завсегдатай
Сообщений: 1253
Регистрация: 26.8.2009

Репутация: 5
Всего: 112



При присваивании
Цитата(Delphist @  9.1.2011,  16:31 Найти цитируемый пост)
Код
b^ := a;

счетчик ссылок на массив a будет увеличен на 1. Легко проверить:
Код

procedure TForm1.Foo(b: PDynArrOfInt);
var
  a: TDynArrOfInt;
begin
  SetLength(a, 3);
  a[0] := 1; a[1] := 2; a[2] := 3;
  ShowMessage(IntToStr(Integer(Pointer(Integer(@a[0]) - 8)^))); // 1 ссылка — a
  b^ := a;
  ShowMessage(IntToStr(Integer(Pointer(Integer(@a[0]) - 8)^))); // 2 ссылки — a и b
end;


При выходе из процедуры счетчик ссылок уменьшится на 1, но не будет равен 0, поскольку внешняя b ссылается на него, поэтому массив не будет освобожден, и данные будут корректны.
PM   Вверх
Delphist
Дата 9.1.2011, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



Цитата(Amphiluke @  9.1.2011,  15:30 Найти цитируемый пост)
При выходе из процедуры счетчик ссылок уменьшится на 1, но не будет равен 0, поскольку внешняя b ссылается на него, поэтому массив не будет освобожден, и данные будут корректны. 

Т.е. массив а выделяется не в памяти локального стека Foo?

Добавлено через 4 минуты и 59 секунд
а счетчик ссылок судя из кода храниться по адресу где был выделен массив со смещением на 8 байт? 


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
lukas
Дата 9.1.2011, 14:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 771
Регистрация: 23.2.2007

Репутация: 3
Всего: 15



Вот так правильно:

Код

type
  PDynArrOfInt = ^TDynArrOfInt;
  TDynArrOfInt = array of Integer;
procedure TForm1.Foo(var b: TDynArrOfInt);
var
  a: TDynArrOfInt;
begin
  SetLength(a, 3);
  a[0] := 1; a[1] := 2; a[2] := 3;
  b^ := copy(a,0,length(a));
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  b: TDynArrOfInt;
begin
  Foo(b);
end;


Это сообщение отредактировал(а) lukas - 9.1.2011, 14:51


--------------------
http://code.google.com/p/orionphp/ - opensource скриптовой язык Orion (аналог PHP) для freepascal/delphi.
PM MAIL WWW   Вверх
Delphist
Дата 9.1.2011, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



А интерфейсы в delphi по этому же принципу работают, в смысле тоже счетчик создается?

Я так понимаю это что-то из серии garbage collection

Добавлено @ 14:51
Цитата(lukas @  9.1.2011,  15:50 Найти цитируемый пост)
Вот так правильно:

не совсем, твой способ медленнее


Это сообщение отредактировал(а) Delphist - 9.1.2011, 14:54


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
Amphiluke
Дата 9.1.2011, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


   ☽
***


Профиль
Группа: Завсегдатай
Сообщений: 1253
Регистрация: 26.8.2009

Репутация: 5
Всего: 112



Цитата(Delphist @  9.1.2011,  17:38 Найти цитируемый пост)
Т.е. массив а выделяется не в памяти локального стека Foo?

Ну, если не ошибаюсь, память под динамические массивы выделяется из «кучи», так что существование динамического массива за пределами локальной области видимости процедуры нормально.

Цитата(Delphist @  9.1.2011,  17:38 Найти цитируемый пост)
а счетчик ссылок судя из кода храниться по адресу где был выделен массив со смещением на 8 байт? 

Угу.
PM   Вверх
Delphist
Дата 9.1.2011, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



Цитата(Amphiluke @  9.1.2011,  16:03 Найти цитируемый пост)
Ну, если не ошибаюсь, память под динамические массивы выделяется из «кучи», так что существование динамического массива за пределами локальной области видимости процедуры нормально.

А как считаешь какой способ копирования лучше, то что я написал или же что lukas, 


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
lukas
Дата 9.1.2011, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 771
Регистрация: 23.2.2007

Репутация: 3
Всего: 15



Delphist 

Copy функция работает с массивами, она довольно быстрая, а то что ты привел, это не копирование, так вообще вроде не делают. Ты правильно используешь ссылку на массив, создав тип PDynArrOfInt, вот и его везде и используй, а T* не используй вообще (если не хочешь копирования).


--------------------
http://code.google.com/p/orionphp/ - opensource скриптовой язык Orion (аналог PHP) для freepascal/delphi.
PM MAIL WWW   Вверх
БелАмор
Дата 9.1.2011, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 5
Всего: 17



Цитата(Delphist @  9.1.2011,  13:31 Найти цитируемый пост)
type
  PDynArrOfInt = ^TDynArrOfInt;

Забудьте о типе "указатель на динамический массив".
Переменная типа "динамический массив" - это уже указатель.

Цитата(Delphist @  9.1.2011,  14:38 Найти цитируемый пост)
Т.е. массив а выделяется не в памяти локального стека Foo?

Переменная - локальная, но ссылается на данные в куче.

Цитата(Delphist @  9.1.2011,  14:38 Найти цитируемый пост)
а счетчик ссылок судя из кода храниться по адресу где был выделен массив со смещением на 8 байт?

Да. Подробнее смотрите моё сообщение по ссылке:
http://www.delphikingdom.com/asp/answer.asp?IDAnswer=62357

Если написать
  a := b;
то a и b будут ссылаться на одни и те-же данные в куче. 
Принципальная разница между строками и динамическими массивами состоит в следующем:
Для строк при изменении данных через одну из переменных, захватывается новая память и модифицируется копия, после чего указатели будут ссылаться уже на разные данные.
Для динамических массивов такого перезахвата не производится, и при изменении данных через одну переменную, изменяться будут и данные, читаемые через другую, т.к. эти переменные будут продолжать ссылаться на одни и те-же данные.

Если интересно про строки, можете посмотреть мой пример здесь:
http://www.delphikingdom.com/asp/articles_...?ArticleID=1206

PM   Вверх
Delphist
Дата 9.1.2011, 16:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



Я объясню зачем такое нужно, например, мы передаем такую структуру:
Код

type 
TRawGroup  = record
....
end;
TDynArrOfRawGroups = array of TRawGroup;
PDynArrOfRawGroups = ^TDynArrOfRawGroups;

PStructrura = ^TStructura;
TStructora = recrod
ParentGroup: integer;
RawGroups: TDynArrOfRawGroups;
end;

procedure TMyClass.MyMethod(pStructura: PStructura);
var
   RawGroups: TDynArrOfRawGroups;
begin

   //здесь что-то делаем и затем заполняем данными RawGroups, а затем вот это:
  if Length(RawGroups) then
  begin 
     SetLength(pStructura^, Length(pStructura^) + 1);
     pStructura^[High(pStructura^)].RawGroups := RawGroups;
  end;
end;

procedure TMyClass.MyMethod(pStructura: TStructura);
begin

    SetLength(pStructura^, Length(pStructura^) + 1);
 
   //здесь что делаем заполняющая данные pStructura^[High(pStructura^)].RawGroups напрямую:
   ...

   //но  я не хочу, чтобы создавался новый элемент в pStructura^, если Length(RawGroups) окажется равным нулю

end;


Добавлено @ 16:34
Цитата(БелАмор @  9.1.2011,  17:18 Найти цитируемый пост)
Для динамических массивов такого перезахвата не производится, и при изменении данных через одну переменную, изменяться будут и данные, читаемые через другую, т.к. эти переменные будут продолжать ссылаться на одни и те-же данные.

Не правда, если сделать так:
Код

  SetLength(a, 3);
  a[0] := 1; a[1] := 2; a[2] := 3;
  b^ := a;
  SetLength(b^, 3);
  a[0] := 4;

  //здесь уже b[0] <> a[0]


И вот для таких то случаев, в локальные процедуры массив лучше передавать через указатель

Это сообщение отредактировал(а) Delphist - 9.1.2011, 16:38


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
БелАмор
Дата 9.1.2011, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 5
Всего: 17



Цитата(Delphist @  9.1.2011,  16:31 Найти цитируемый пост)
Не правда, если сделать так:  SetLength(a, 3);
  a[0] := 1; a[1] := 2; a[2] := 3;
  b^ := a;
  SetLength(b^, 3);
  a[0] := 4;

  //здесь уже b[0] <> a[0]

Я допустил неточность. Я имел в виду изменение отдельных элементов массива без изменения длины самого массива.
В случае вызова SetLength, естественно, происходит перезахват памяти и переменные уже будут ссылаться на разные данные.

Цитата(Delphist @  9.1.2011,  16:31 Найти цитируемый пост)
И вот для таких то случаев, в локальные процедуры массив лучше передавать через указатель

Для таких случаев массив в процедуру следует передавать как var-параметр. А внутри процедуры можно либо работать напрямую с оригинальным массивом, либо завести локальный, работать с ним, а потом присвоить переданной перменной.
Кстати, обратите внимание на модуль Types
Там, в частности, уже объявлен тип:
TIntegerDynArray = array of Integer;

Соответственно, оптимальным, в зависимости от конкретных требований, на мой взгляд, будет один из вариантов:

Код

procedure Foo1(var b: TIntegerDynArray);
var
  a: TIntegerDynArray;
begin
  SetLength(a, 3);
  a[0] := 1;
  a[1] := 2;
  a[2] := 3;

  b := a;
end;

procedure Foo2(var b: TIntegerDynArray);
begin
  SetLength(b, 3);
  b[0] := 1;
  b[1] := 2;
  b[2] := 3;
end;

PM   Вверх
Delphist
Дата 9.1.2011, 17:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



var для динам. массивов в параметрах функции вообще нет смысла использовать!

Это сообщение отредактировал(а) Delphist - 9.1.2011, 17:47


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
lukas
Дата 9.1.2011, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 771
Регистрация: 23.2.2007

Репутация: 3
Всего: 15



Цитата(Delphist @  9.1.2011,  17:46 Найти цитируемый пост)
var для динам. массивов в параметрах функции вообще нет смысла использовать!


Если там будет const или без (не помню), будет происходить постоянное копирование массива перед вызовом, я проверял.



--------------------
http://code.google.com/p/orionphp/ - opensource скриптовой язык Orion (аналог PHP) для freepascal/delphi.
PM MAIL WWW   Вверх
БелАмор
Дата 9.1.2011, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 209
Регистрация: 10.6.2010
Где: Россия

Репутация: 5
Всего: 17



Цитата(Delphist @  9.1.2011,  17:46 Найти цитируемый пост)
var для динам. массивов в параметрах функции вообще нет смысла использовать!

Хм... Почему? Хотя бы минимальное обоснование... Вы точно не путаете с классовыми переменными?

Цитата(lukas @  9.1.2011,  18:05 Найти цитируемый пост)
Если там будет const или без (не помню), будет происходить постоянное копирование массива перед вызовом, я проверял.

Передача параметров без спецификатора, с const, и с var - это три большие разницы... При const, и var не копируется вообще ничего, именно поэтому, в частности, с этими спецификаторами рекомендуют передавать, например, записи...
PM   Вверх
Delphist
Дата 9.1.2011, 20:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphist Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2145
Регистрация: 3.2.2004
Где: всегда в сети

Репутация: 2
Всего: 3



Цитата(БелАмор @  9.1.2011,  19:40 Найти цитируемый пост)
Хм... Почему?


Да очень просто - смысл использования var. var для массива зачем? чтобы изменить адрес массива - но это если и нужно то очень редко


--------------------
ProcessInfo 1-ая моя программа (аналог spyxx.exe с гораздо большим функц-ом - внедрение dll в адр. простр. процесса, перехват API-функций, разбор приложения на окна мн.др).
Когда-то давным-давно использовал это...
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0615 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.