Я в шоке или подозрение на менеджер памяти o.O

Вопросы программирования и использования среды Lazarus.

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

Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 13.03.2010 12:34:31

Ничего не понимаю. Я динамически создаю строки. Заношу в списки.
В т.ч., указатели на строки приходится хранить в ComboBox.Items.Objects.
Для этого я создал класс, который организует работу с памятью, чтобы утечек не было.
ЦБоксы заносятся в список. Когда они очищаются, объект удаляет строки из Objects.
Английским по белому написано, что Objects не отвечает за удаление объектов.
В т.ч., в коде библиотеки.
Следовательно, нужно возвращать память, выделенную под строки.
TList, тем более, ничего не удаляет. :-\

Я затрахался. Дня два-три парюсь.
Проштудировал всю эту чёртову разномастную помойку функций, из строковой библиотеки, которые делают одно и то же. Проверил разные. Написал свои. Всё равно, бэ!

В итоге я пришёл к тому, что мои функции почти не отличаются от библиотечных и просто сделал обёртку над
New/Dispose.
И, всё равно, вылетает SEGFAULT.

Самое офигительное, что если закомментировать одну строчку(!), всё стабильно работает.
Код: Выделить всё
procedure strdel(const ps: PString);
begin
  //if (ps <> nil) then Dispose(ps);
end;


Но утечки... Когда я копался в библиотеке, обнаружил некий TMemoryManager. Не обратил внимания.
Типа, отвечает за работу Freemem/Getmem. К тому же, он содержит указатели на системные функции.

Но, я посмотрел в диспетчере...
Почему-то, после нескольких показов окна, при которых перезаполняются ЦБоксы, объём памяти не возрастает...
Неужели там реализовано что-то вроде сборки мусора?

Просветите, чтобы я мог со спокойной совестью забить на удаление строк.
Последний раз редактировалось А.Н. 13.03.2010 16:24:37, всего редактировалось 1 раз.
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение Sergei I. Gorelkin » 13.03.2010 13:05:23

Да, память под строки типа AnsiString, WideString, UnicodeString выделяется/освобождается автоматически. Только это не сборка мусора, а подсчет ссылок.
Результат совместно использования строк, указателей и new/dispose без исходного кода предсказать не берусь.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 13.03.2010 13:17:37

Да, память под строки типа AnsiString, WideString, UnicodeString выделяется/освобождается автоматически. Только это не сборка мусора, а подсчет ссылок.

Это я видел. Класс TAnsiString. Интересно, что "Лазарь" их, как ключевые слова выделяет...
Но разьве string - это тоже самое, что AnsiString?
Вообще, как здесь выглядит string в памяти? Это Pascal-строка? Есть ли ограничения на длину?

Результат совместно использования строк, указателей и new/dispose без исходного кода предсказать не берусь.

Так, в любом случае, строки с указателями придётся использовать. Строка, ведь это, по идее, указатель?
Чёртов Pascal, ну зачем столько типов строк?!

Добавлено спустя 7 минут:
Например, есть код:
Код: Выделить всё
id             := strsnew(FieldByName(id_field).AsString);
for i := 0 to cb_count - 1 do cb[i].AddItem(display_label, id);


Ведь я же не могу сделать так, например? :
Код: Выделить всё
// Ну, это грубо. Синтаксически, пожалуй, будет неверно. Но, даже если с локальной переменной...
id             := @(FieldByName(id_field).AsString);
for i := 0 to cb_count - 1 do cb[i].AddItem(display_label, id);
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение Sergei I. Gorelkin » 13.03.2010 14:34:47

string - то же самое, что AnsiString только в режиме {$H+}. При программировании в Лазаре это режим по умолчанию.
В памяти это указатель на первый символ, перед которым находятся счетчик ссылок и длина. Пустая строка - это nil. В конце непустой строки автоматически добавляется нулевой символ.
А.Н. писал(а):Например, есть код:
id             := strsnew(FieldByName(id_field).AsString);
for i := 0 to cb_count - 1 do cb[i].AddItem(display_label, id);

В целом подход правильный. Но поведение этого кода зависит от типа переменной id и от того, что происходит в ф-ции strsnew.

Самое надежное - объявить класс, хранящий строку. Будет занимать на 8 байт больше памяти, зато типобезопасно:
Код: Выделить всё
type
  TWrapper = class(TObject)
  public
    str: string;
  end;

// создание
var
  w: TWrapper;
begin
  w := TWrapper.Create;
  w.str := FieldByName(...).AsString;
  cb[i].AddItem(display_label, w);
end;

// уничтожение
  for j:=0 to cb[i].Count-1 do
    cb[i].Objects[j].Free;      // память строки освобождается
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 13.03.2010 15:03:10

string - то же самое, что AnsiString только в режиме {$H+}. При программировании в Лазаре это режим по умолчанию.

А что за режим {$H+}? У меня режим {$MODE Delphi}. Проект был конвертирован, так и осталось.

В памяти это указатель на первый символ, перед которым находятся счетчик ссылок и длина. Пустая строка - это nil.

Неприятно то, что я получаю не указатель на строку с размером, когда беру её адрес, а указатель на второй символ. Хотя, конечно, строки индексированы с 1... Но, как-то это неочевидно, что надо, например, назад вернуться на сколько-то байт, чтобы освободить всю выделенную память. Функции какие-то хитрые со строками работают. Нет бы, один PChar и всё... Ну, плюс классы.
Конечно, понятно, что это ещё ради обратной совместимости, но, так всё запутано. :-

Кстати, там тип размера Cardinal. Ведь он занимает больше, чем один байт...
Странно... Он же, вроде, не на всех платформах одинаковый...

В конце непустой строки автоматически добавляется нулевой символ.

Чем это реализовано?

В целом подход правильный. Но поведение этого кода зависит от типа переменной id и от того, что происходит в ф-ции strsnew.


Если вам это будет интересно, вот код:
Код: Выделить всё
//---------------------------------------------------------------------------
function strsnew(const s: string): PString;
begin
  New(Result);
  if (Result <> nil) then
    begin
      Result^ := s;
    end;
end;
//---------------------------------------------------------------------------
procedure TDBListFiler.FillListFromDB(const id_field, display_field: string;
  query: TZAbstractRODataset; cb: array of TCustomComboBox);
var id: pointer;
    display_label: string;
    i, cb_count: integer;
begin
  cb_count := Length(cb);
  try
    for i := 0 to cb_count - 1 do
      begin
        // Вначале очищаю
        ClearCb(cb[i], false);
        cb[i].DoubleBuffered := true;
        cb[i].Items.BeginUpdate();
      end;
  with query do
    begin
      Open();
      First();
      while (not query.EOF) do
        begin

          display_label  := FieldByName(display_field).AsString;
          // Предыдущий кретин-разработчик сделал поля идентификаторов в
          // нек. таблицах, типа varchar.
          id             := strsnew(FieldByName(id_field).AsString);
          for i := 0 to cb_count - 1 do cb[i].AddItem(display_label, id);
          Next();
        end;
    end;
  // Затем, добавляю в список.
  // !!!Внимание. Вероятны утечки, при ошибке.
  AddCbToList(cb);

  finally
    for i := 0 to cb_count - 1 do cb[i].Items.EndUpdate();
  end;

  try
    for i := 0 to cb_count - 1 do cb[i].ItemIndex := 0;
  except
  end;
end;
//---------------------------------------------------------------------------


Код: Выделить всё
  for j:=0 to cb[i].Count-1 do
    cb[i].Objects[j].Free;      // память строки освобождается

Хм... Интересно. Потом подумаю.
Вероятно, переделаю сходным образом. Спасибо.
Правда, не очень нравится, что приходится писать враппер для хранения всего лишь строки. :(

Добавлено спустя 24 минуты 5 секунд:
Да, помимо хранения в Objects, у меня есть индексированный список строк... :-\ Напрягает.
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение Sergei I. Gorelkin » 13.03.2010 16:07:34

А.Н. писал(а):А что за режим {$H+}? У меня режим {$MODE Delphi}. Проект был конвертирован, так и осталось.

Вот лучше после {$MODE Delphi} добавить еще {$H+}. Странно, что оно не добавилось при конвертации.
При {$H+} тип string равен AnsiString, при {$H-} - ShortString.
А.Н. писал(а):Кстати, там тип размера Cardinal. Ведь он занимает больше, чем один байт...Странно... Он же, вроде, не на всех платформах одинаковый...

Ничего странного, ограничения на длину строки нет, строка может занимать хоть все адресное пространство... если операционная система позволит.

А.Н. писал(а):В конце непустой строки автоматически добавляется нулевой символ.Чем это реализовано?

Все базовые операции над строками преобразуются в вызовы служебных процедур из RTL. Эти процедуры поддерживают правильное состояние служебных полей (длина, счетчик ссылок, нулевой терминатор).

А.Н. писал(а):Правда, не очень нравится, что приходится писать враппер для хранения всего лишь строки.

Не нравится class - можно использовать record. Получится практически то же самое, что уже написано, но без типа PString.
Использования PString лучше избегать, особенно в режиме delphi, где компилятор практически не отличает указатели от того, на что они указывают.

Еще вариант - сложить все строки в отдельный TStringList, а в свойство Objects помещать индексы этих строк.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 13.03.2010 16:21:32

Вот лучше после {$MODE Delphi} добавить еще {$H+}. Странно, что оно не добавилось при конвертации.
При {$H+} тип string равен AnsiString, при {$H-} - ShortString.

Хм... Кстати, в новых модулях: {$mode objfpc}{$H+} . Может тогда, вообще везде {$MODE Delphi} заменить на режим objfpc? Не повлечёт ли это новых побочных эффектов?

Ничего странного, ограничения на длину строки нет, строка может занимать хоть все адресное пространство... если операционная система позволит.

Хм... А функции библиотек используют нулль-завершённые строки, не обращая внимания на байты размера?

Все базовые операции над строками преобразуются в вызовы служебных процедур из RTL. Эти процедуры поддерживают правильное состояние служебных полей (длина, счетчик ссылок, нулевой терминатор).

Кстати, я пытался сделать что-то подобное для PChar (похоже на библиотечные функции). Но, всё равно.
Вылетало с ошибкой... Хотя, может, я где напортачил..?
Код: Выделить всё
//---------------------------------------------------------------------------
function strsnew(const s: string): pchar;
// Создаёт строку Pascal/C типа. Вначале - число символов.
// В конце - нуль символ.
var
  len: longint;
  size: longint;
begin
  Result := nil;
  len    := Length(s);
  if (len = 0) then exit;
  // Result := StrAlloc(len);
  // len + 1 - в конце строки #0 символ
  // Длина считается без нуль-символа.
  size := (len + 1) * SizeOf(char) + SizeOf(cardinal);
  Getmem(Result, len);
  Cardinal(Pointer(Result)^) := size;
  Inc(Result, SizeOf(cardinal));
  if (Result <> nil) then
    begin
      strmove(Result, PChar(s), len);
      Result[len + 1] := #0;
    end;
end;
//---------------------------------------------------------------------------
procedure strdel(ps: pchar);
var p0: pchar;
begin
  if (ps <> nil) then
   begin
     Dec(ps, SizeOf(Cardinal));
     // +1 - #0 в конце
     Freemem(p0, SizeOf(Char) * (Cardinal(pointer(ps)^) + 1));
     ps := nil;
   end;
end;
//---------------------------------------------------------------------------


Еще вариант - сложить все строки в отдельный TStringList, а в свойство Objects помещать индексы этих строк.

Вариант достаточно сложный. Поскольку, ComboBox'ов много и строки берутся из разных таблиц.
Легко запутаться с индексами.

Не нравится class - можно использовать record. Получится практически то же самое, что уже написано, но без типа PString.

Не нравится, вообще, wrapper к строке делать. :) К тому же, вроде нет разницы м. class и record?
Хотя, автоматическое управление памятью имеет плюсы (например, мне не приходится очищать Objects, при закрытии программы, т.е. исключены разборки с порядком уничтожения ComboBox и их Objects), это слишком сложно...
Обидно, что default есть только для массивов, а не для функций, к примеру...
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение alexrayne » 13.03.2010 16:44:27

Насколько я понимаю беда вылезает изза преобразования типов указателей из AnsiString в TObject, что при этом происходит со счетчиком сцылок?
имхо, при освобождении строки сохраненной в видепростого указателя непонятно как преобразовывать типы ибо

ObjectVar := TObject(AnsiVar);
здесь указатель AnsiVar становится несцылочным перед присваиванием и в итоге количество сцылок неменяется, а обратное преобразование

AnsiVar := AnsiString(ObjectVar)
должно увеличивать количество сцылок на строку ибо указатель на строку появляется ПЕРЕД присваиванием,
насколько я понимаю это правило действует и при передаче строки в параметрах.
вобщем налицо асимметрия преобразования и подсчет сцылок.
я для того чтобы непарится с этим делал примерно так

var
AnsiVar : AnsiString;
ObjectVar : TObject absolute AbsiVar;
begin

AnsiVar := GetSomeString();
List.Objects[idx] := ObjectVar;

ObjectVar := List.Objects[idx];
SetLength(AnsiVar,0);

end;
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 13.03.2010 17:20:40

AnsiVar := AnsiString(ObjectVar)
должно увеличивать количество сцылок на строку ибо указатель на строку появляется ПЕРЕД присваиванием,
насколько я понимаю это правило действует и при передаче строки в параметрах.
вобщем налицо асимметрия преобразования и подсчет сцылок.

Ой, ёёё... Значит, менеджер не будет уничтожать динамически выделенную строку?
Хм... Но, с другой стороны, количество выделенной памяти не меняется, при многократных заполнениях ЦБокса.
Асимметрия здесь в сторону большего, чем нужно, числа ссылок.
Т.е., delstr, в таком случае, не вылетал бы в SEGFAULT.

К тому же, почему, если где-то увеличивается количество ссылок, к примеру, при использовании строки после преобразования типа, то, почему там же оно не будет уменьшаться, когда строка уже больше не потребуется?
%-|
Чего-то я порядком запутался.

var
AnsiVar : AnsiString;
ObjectVar : TObject absolute AbsiVar;

В каждой функции тогда придётся это помещать. :( Сложно.
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение Sergei I. Gorelkin » 13.03.2010 23:37:13

А.Н. писал(а):Хм... Кстати, в новых модулях: {$mode objfpc}{$H+} . Может тогда, вообще везде {$MODE Delphi} заменить на режим objfpc? Не повлечёт ли это новых побочных эффектов?

Компилятор будет строже проверять код, и скорее всего просто так оно не соберется. При присвоении обработчиков событий придется добавлять '@': Button1.OnClick := @Button1Click;. Название аргумента метода объекта не сможет совпадать с названием поля этого объекта. Не будет неявного разыменования указателей. И еще пара подобных нюансов.

А.Н. писал(а):Хм... А функции библиотек используют нулль-завершённые строки, не обращая внимания на байты размера?

Это смотря каких библиотек. Все паскалевские функции, принимающие "const s: string", используют размер, поэтому строки могут содержать нули внутри, и по сути, их можно использовать для хранения произвольных данных. В то же время эти строки очень хорошо передаются в сишные библиотеки, потому что с их точки зрения переменная типа AnsiString - это нуль-терминированный PChar.

А.Н. писал(а):Кстати, я пытался сделать что-то подобное для PChar (похоже на библиотечные функции). Но, всё равно.Вылетало с ошибкой... Хотя, может, я где напортачил..?

Ясен перец, в процедуре strdel переменная p0 нигде не присваивается. Возможно, в этом и причина всей истории.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 14.03.2010 00:11:55

Компилятор будет строже проверять код, и скорее всего просто так оно не соберется. При присвоении обработчиков событий придется добавлять '@': Button1.OnClick := @Button1Click;. Название аргумента метода объекта не сможет совпадать с названием поля этого объекта. Не будет неявного разыменования указателей. И еще пара подобных нюансов.

Это всё, в принципе, нормально. А какая ещё пара нюансов?

их можно использовать для хранения произвольных данных.

Ну да, правда, по размеру сильно ограниченных. А если данные выйдут за этот размер? Получается, что некоторые библиотечные функции будут работать правильно, а некоторые, обрезать строку..?

Ясен перец, в процедуре strdel переменная p0 нигде не присваивается. Возможно, в этом и причина всей истории.

Ой, извиняюсь. %-| Просмотрел и не поправил. Изначально был ps. Не помню для чего p0 вводил.
Было так: Freemem(ps, SizeOf(Char) * (Cardinal(pointer(ps)^) + 1));
И тоже самое. :( Справедливости ради, я до strdel пользовался библиотечной StrDispose. Тоже вылетало.
Так что, не в этом дело, видимо...
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение Sergei I. Gorelkin » 14.03.2010 01:04:08

А.Н. писал(а):Это всё, в принципе, нормально. А какая ещё пара нюансов?

Ну не помню я всего наизусть :) Но код, исправленный для режима objfpc, потом нормально работает обратно в Дельфи, за исключением этого злополучного "@" перед методами.

А.Н. писал(а):Ну да, правда, по размеру сильно ограниченных. А если данные выйдут за этот размер? Получается, что некоторые библиотечные функции будут работать правильно, а некоторые, обрезать строку..?

Размер AnsiString ограничен только доступной памятью. Естественно, место надо выделять заранее, для этого есть ф-ция SetLength. Если в строке есть нули, ф-ции, принимающие PChar, с ней будут работать неправильно.

А.Н. писал(а):И тоже самое. Справедливости ради, я до strdel пользовался библиотечной StrDispose. Тоже вылетало.Так что, не в этом дело, видимо...

Если присмотреться, там еще хватает косяков. Например, в strsnew считается размер size вроде правильно, но памяти выделяется вместо этого len байт (а должно быть size). В strdel второй аргумент FreeMem - считается без учета sizeof(Cardinal) байт, в которых хранится длина.

Вообще, StrNew и StrDispose должны работать в этом сценарии, при условии что они взяты из модуля SysUtils.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение alexrayne » 14.03.2010 01:48:07

В каждой функции тогда придётся это помещать. :( Сложно.


судя по тому что Вы наворачиваете, ето еще сложнее получается.
можно наверное перегрузить класс TObjectList в который вы строки складываете и ввести там пару своих методов, которые будут заниматься корректным преобразованием типов и возвращать\сохранять строки в качестве параметров.
если лень перекрывать класс, можно сделать процедуры вроде
GetStr(Src : TList; idx : integer) : AnsiString;
PutStr(Src : TList; idx : integer; value : AnsiString);
которые будет скрывать все преобразования типов.
кстати отсутствие инкремента сцылки при сохранении строки в List.Objects[] может приводить к неверному освобождению строки, ибо невидно остается что гдето используется. чтобы етого небыло надо наверно обманывать следилку сцылок, вроде такого

var
AnsiVar : AnsiString;
ObjVar : TObject absolute AnsiVar;
begin
ansivar := value;
list.objects[] := ansivar;
objvar := nil;
end;
здесь счетчик сцылок увеличивается при присваивании ansivar, но неуменьшается обратно при выходе из процедуры ибо мы последним присваиванием стираем доступ к строке, но реально она ведь уже лежит в списке, посему значение счетчика корректно.
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение А.Н. » 14.03.2010 10:51:29

Sergei I. Gorelkin писал(а):Но код, исправленный для режима objfpc, потом нормально работает обратно в Дельфи, за исключением этого злополучного "@" перед методами.

Да мне уже не важна совместимость с Delphi. Исправил. Несколько явных преобразований типа пришлось добавить, всё заработало. :)
Вылетает, правда на этом месте:
with cbPolicyHolder do Params[0].AsString := PString(Items.Objects[ItemIndex])^;
Но не всегда... Там, в окрестностях, просто где-то баг.
Но, видимо, без посильного вклада проблем со строками не обошлось.

Размер AnsiString ограничен только доступной памятью. Естественно, место надо выделять заранее, для этого есть ф-ция SetLength. Если в строке есть нули, ф-ции, принимающие PChar, с ней будут работать неправильно.

Ну, длина-то хранится в нулевом байте, как обычно, а не в какой-то структуре?
Точнее, получается в двух байтах... Обычно.

Какое-то там руководство писал(а):Тип cardinal используется на данный момент как тип longword. Определения типов cardinal и integer могут изменяться от одной архитектуры к другой и от одного компилятора к другому. Они обычно имеют тот же размер, что и целевая архитектура.

Т.е., обычно длина строки ограничена 64 Кб?

Если присмотреться, там еще хватает косяков. Например, в strsnew считается размер size вроде правильно, но памяти выделяется вместо этого len байт (а должно быть size). В strdel второй аргумент FreeMem - считается без учета sizeof(Cardinal) байт, в которых хранится длина.

Такое впечатление, что я пьяный это писал. :( Блин. Башка у меня не работает.

Вообще, StrNew и StrDispose должны работать в этом сценарии, при условии что они взяты из модуля SysUtils.

В том-то и дело, что не работают. Я бы не стал тогда делать самостоятельно. Причём, есть ещё StrAlloc.
С ним, вместо самостоятельного выделения памяти, та же фигня: SEGFAULT.

alexrayne писал(а):можно наверное перегрузить класс TObjectList в который вы строки складываете и ввести там пару своих методов, которые будут заниматься корректным преобразованием типов и возвращать\сохранять строки в качестве параметров.

А возможно про это поподробнее? Что значит "перегрузить класс"? Разьве есть что-то вроде перегрузки функций, но только с классами?
И мне не придётся наследовать, а, затем переделывать TComboBox?

можно сделать процедуры вроде
GetStr(Src : TList; idx : integer) : AnsiString;
PutStr(Src : TList; idx : integer; value : AnsiString);
которые будет скрывать все преобразования типов.

Хм... Пожалуй... В них уже обёртку на строкой...

чтобы етого небыло надо наверно обманывать следилку сцылок, вроде такого

Мда... Героически преодолевать. :(

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

Ага, понял. Но ведь получается, что если этого не сделать, число ссылок после выхода уменьшится.
Следовательно рано или поздно оно станет нулевым.
И менеджер должен разрушить строку и освободить память.
Т.е., получается, что если этого не сделать, в данном случае, работать всё если и будет, то "святым духом"?
Только до того как кто-то решит выделить память по тому же адресу и записать туда что-то?
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Я в шоке или подозрение на менеджер памяти o.O

Сообщение alexrayne » 14.03.2010 20:31:57

alexrayne писал(а):можно наверное перегрузить класс TObjectList в который вы строки складываете и ввести там пару своих методов, которые будут заниматься корректным преобразованием типов и возвращать\сохранять строки в качестве параметров.


А возможно про это поподробнее? Что значит "перегрузить класс"? Разьве есть что-то вроде перегрузки функций, но только с классами?
И мне не придётся наследовать, а, затем переделывать TComboBox?

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

Ага, понял. Но ведь получается, что если этого не сделать, число ссылок после выхода уменьшится.
Следовательно рано или поздно оно станет нулевым.
И менеджер должен разрушить строку и освободить память.
Т.е., получается, что если этого не сделать, в данном случае, работать всё если и будет, то "святым духом"?
Только до того как кто-то решит выделить память по тому же адресу и записать туда что-то?

ну да так и есть. вобщем здесь 2 проблемы которые надо обходить :
1) корректный подсчет сцылок при сохранении строки в комбосписке. это толькочо было описано
2) корректное удаление строки из комбосписка. - чтото вроде этого было описано в середине топика.

получается что если нам надо взять строку из списка
ansivar := ansistring(list.opbjects[idx]);
корректно подсчитает сцылки здесь - счетчик сцылок нормально увеличится.

но вот как корректно освободить строку или изменить ее значение? для етого надо непросто скопировать строку из списка а взять ее из списка как есть и только тогда удалить/изменить. как ето было ранее описано:
var
AnsiVar : AnsiString;
ObjectVar : TObject absolute AbsiVar;
begin

ObjectVar := List.Objects[idx];
AnsiVar := NewValue; //здесь сцылки корректно уменьшаются и увеличиваются
//если старая строка более нигде не используется она освобождается.
List.Objects[idx] := ObjectVar;
end;


собсно последнее наверное есть универсальное решение процедуры присваивания строки элементу списка. и кстати если используется фрюха, эту процедуру наверно можно сделать inline, ибо она практически несодержит реального кода, все чистой воды обман компилятора.
alexrayne
постоялец
 
Сообщения: 125
Зарегистрирован: 03.12.2008 16:56:26

След.

Вернуться в Lazarus

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

Сейчас этот форум просматривают: Google [Bot], MailRu[bot] и гости: 44

Рейтинг@Mail.ru