TList проблема создания

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

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

Юрий
новенький
Сообщения: 11
Зарегистрирован: 03.04.2022 02:32:16

TList проблема создания

Сообщение Юрий »

Добрый день, всем

Господа, можете подсказать, почему код ниже в Lazarus выдаёт ошибку а в Delphi нет ?

Код: Выделить всё

procedure AAA;
var
  theClass: TClass;
  L: TList;
begin
  theClass := TList;
  L := TList(theClass.Create);     //  L := TList.Create;
  ShowMessage(L.ClassName);   
  if L.Count = 0 then    // <-- Access violation reading from address $0000000000000010.
    L.Add(nil);
end;    
Прямо какая-то досада непонятная... :(
RRYTY
постоялец
Сообщения: 253
Зарегистрирован: 25.12.2021 09:00:32

Сообщение RRYTY »

Наверно, потому что TClass нигде не определен.

А это вообще непонятно, что имеется ввиду:

Код: Выделить всё

theClass := TList;
Сразу предупрежу: про Delphi не знаю ничего.
Юрий
новенький
Сообщения: 11
Зарегистрирован: 03.04.2022 02:32:16

Сообщение Юрий »

Если бы он небыл бы определён, то тогда бы проект не скомпилился...

в Lazarus :

Код: Выделить всё

objpash.inc
...
     type
       TextFile = Text;

       { now the let's declare the base classes for the class object
         model. The compiler expects TObject and IUnknown to be defined
         first as forward classes }
       TObject = class;
       IUnknown = interface;

       TClass  = class of tobject;
       PClass  = ^tclass;    
Точно также как и в Delphi :

Код: Выделить всё

unit System;
...
type

  TObject = class;

  TClass = class of TObject;

>>А это вообще непонятно, что имеется ввиду: theClass := TList;

Это имеется ввиду переменная типа "Тип данных",
Стандартный тип данных,
в турбо паскаль появился а может и раньше...
RRYTY
постоялец
Сообщения: 253
Зарегистрирован: 25.12.2021 09:00:32

Сообщение RRYTY »

Тогда так:

Код: Выделить всё

L:= TList(theClass.Create).Create;
DedFrend
постоялец
Сообщения: 157
Зарегистрирован: 25.11.2018 11:21:50

Сообщение DedFrend »

а что там в uses?
iskander
энтузиаст
Сообщения: 627
Зарегистрирован: 08.01.2012 18:43:34

Сообщение iskander »

Юрий писал(а):Господа, можете подсказать, почему код ниже в Lazarus выдаёт ошибку а в Delphi нет ?
...
Прямо какая-то досада непонятная...
А которая Delphi, интересно?
Имхо подобные штуки могут работать только если конструктор базового класса виртуальный.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Юрий писал(а):Господа, можете подсказать, почему код ниже в Lazarus выдаёт ошибку а в Delphi нет ?
Потому что Lazarus приличная IDE, а Delphi - нет. Delphi любит чтобы пользователь побольше мучался.
iskander писал(а):Имхо подобные штуки могут работать только если конструктор базового класса виртуальный.
Ого. Я утром читал чуть чуть, про эту обертку и там ничего об этом не было. Но правда.. работает код

Код: Выделить всё


TComponent
....
constructor Create(AOwner: TComponent); virtual;

procedure TForm1.Button3Click(Sender: TObject);
var
  theClass: TControlClass;
  L: TComboBox;
  T:TObject;
begin
  theClass := TComboBox;
  t        := theClass.Create(self);
  L := TComboBox(t);     //  L := TList.Create;
  ShowMessage(L.ClassName);
  if L.Items.Count = 0 then    // <-- Access violation reading from address $0000000000000010.
    L.Items.Add('-');
end; 
Юрий
новенький
Сообщения: 11
Зарегистрирован: 03.04.2022 02:32:16

Сообщение Юрий »

Sharfik писал(а):
Юрий писал(а):Господа, можете подсказать, почему код ниже в Lazarus выдаёт ошибку а в Delphi нет ?
Потому что Lazarus приличная IDE, а Delphi - нет. Delphi любит чтобы пользователь побольше мучался.
iskander писал(а):Имхо подобные штуки могут работать только если конструктор базового класса виртуальный.
Ого. Я утром читал чуть чуть, про эту обертку и там ничего об этом не было. Но правда.. работает код
>>Но правда.. работает код
Сделал по аналогии, работает (везде Laz64,D2007 32,XE8 64/32)

Код: Выделить всё

type
  TListClass = class of TList; 

procedure TForm1.Button2Click(Sender: TObject);
var
  theClass: TListClass;
  L: TList;
  T: TObject;
begin
  theClass := TList;  // или наследники TList
  t        := theClass.Create;
  L        := TList(t);
  ShowMessage(t.ClassName);
  if L.Count = 0 then    // <-- Всё хорошо
    L.Add(nil);
...
Но есть момент что TListClass = class of TList; нужно самому определять. А в проекте где я выхватил эту ошибку, нужно будет это в кучи модулях прописывать что не очень... Это я для наглядности в одну процу засунул, подумаю…
Вам спасибо

>>Потому что Lazarus приличная IDE, а Delphi - нет. Delphi любит чтобы пользователь побольше мучался.
Тут я с вами не согласен. И та и та отличные среды, где-то в одной что-то удобнее, где-то в другой…
Тут вопрос выбора больше политически-идеологический… Моё личное мнение что после наступление примерного момента когда Убунта(и аналоги) стали по качеству луче чем Винда… Сначала Винда со своими обновлениями и инновациями пойдёт постепенно в Ж… А потом и Делфи потянется туда же… А для нас это процесс пойдёт быстрее, плоды начали всходить от санкций и импортозамещений…

Добавлено спустя 10 минут 10 секунд:
RRYTY писал(а):Тогда так:

Код: Выделить всё

L:= TList(theClass.Create).Create;
Удивительно но работает! (везде Laz64,D2007 32,XE8 64/32)

Код: Выделить всё

procedure TForm1.Button3Click(Sender: TObject);
var
  theClass: TClass;
  L: TList;
begin
  theClass := TList;

  //L := TList.Create;
  //L := TList(theClass.Create);
  L := TList(theClass.Create).Create;

  ShowMessage(L.ClassName);
  if L.Count = 0 then
    L.Add(nil);

  ShowMessage(IntToStr(L.Count));
  L.Free;
end;
Я, правда, не понимаю почему...
Утечек памяти нет
Как-то это противоречит логике. :shock:
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение wavebvg »

Юрий писал(а):
Sharfik писал(а):
Юрий писал(а): Удивительно но работает! (везде Laz64,D2007 32,XE8 64/32)
Всё зависит от менеджера памяти и включенных опций безопасности и т.п.

0. TObject.Create и TList.Create -- статические методы. Значит TList(theClass.Create); вызовет только TObject.Create выделит памяти для TObject.

1. TList(theClass.Create).Create; вызовет TObject.Create выделит памяти для TObject, после чего вызовет конструктор для TList.Create и попортит память за пределами класса.

2. В Дельфе TList класс в себе и ничего в конструкторе интересного не делает, в отличии от FPC-го, который, по сути, является делегированной обёрткой над TFPList.

3. Если обращение TFPList(nil).Count у Вас работает, т.е. чтение из адреса 0+Смещение FCount (+$10 судя из поста топикстартера) из TFPList, то нет AV, в противном случае есть.

PS Пост обновлён, т.к. TList(theClass.Create).Create; это сильно!
Последний раз редактировалось wavebvg 17.12.2022 16:45:26, всего редактировалось 1 раз.
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Юрий писал(а):>>Потому что Lazarus приличная IDE, а Delphi - нет. Delphi любит чтобы пользователь побольше мучался.
Тут я с вами не согласен. И та и та отличные среды, где-то в одной что-то удобнее, где-то в другой…
Тут вопрос выбора больше политически-идеологический… Моё личное мнение что после наступление примерного момента когда Убунта(и аналоги) стали по качеству луче чем Винда… Сначала Винда со своими обновлениями и инновациями пойдёт постепенно в Ж… А потом и Делфи потянется туда же… А для нас это процесс пойдёт быстрее, плоды начали всходить от санкций и импортозамещений…
При переходе с Delphi на Lazaasu о программировании узнаешь гораздо больше и код становится более продуманным.
Понятие "удобно" это путь к деградации. Вместо того чтобы учиться и изучать новое, люди упираются в одно какое то ПО и перестают развиваться. А дальше вместе с ними вся компания потенциально угасает. Сейчас это особенно заметно, когда люди вместо того чтобы попробовать что то новое начинают предлагать "давайте взломанный установим".
Юрий писал(а):L:= TList(theClass.Create).Create;
По сути бесполезный и не правильный код. Суть идеи TClass чтобы работать с абстрактным типом класса. Делать какие то манипуляции не ориентируясь на процедуры класса конкретного. А в указанном коде, это все теряется.
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Код: Выделить всё

theClass := TList;
:shock:
Присвоить экземпляру тип ? Это вообще как ????
===============================

Код: Выделить всё

  L:= TList(theClass.Create).Create;
А это вообще ИМХО ересь !
( Работать будет но в начале тупо сработает TClass(theClass).Create потом TList.Create; результат будет точно таким же как если сделать примерно так: L:= TList.Create; theClass:= TClass(L); ситуация чуть сложнее потому что theClass "переобувается в полете" но смысла в этой строке всеравно немного )

Имеет какой-то смысл только если нужно что-бы вначале отработал TClass.Create, а потом "поверх" TList.Create; но это по моему полный бред, потому что TList если я ничего не путаю наследник TClass и скорее всего и так вызывает код TClass.Create "по inherited " . :idea:
Зы
Не много подумал... Хм ! Идея понятна TClass как бы "базовый тип" но все равно странно.. Зачем нужны такие сложности ? :roll:
Аватара пользователя
Sharfik
энтузиаст
Сообщения: 836
Зарегистрирован: 20.07.2013 01:04:30

Сообщение Sharfik »

Alex2013 писал(а):Зачем нужны такие сложности ?
Чтобы хакеры из Microsoft могли в любой момент ничего не зная программе управлять ею через абстрактные процедуры :roll: :mrgreen:
Юрий
новенький
Сообщения: 11
Зарегистрирован: 03.04.2022 02:32:16

Сообщение Юрий »

Alex2013 писал(а):

Код: Выделить всё

theClass := TList;
:shock:
Присвоить экземпляру тип ? Это вообще как ????
Я не понимаю степень вашей удивлённости.
Ну это как бы базовые вещи языка..., можно сказать "типизированный указатель", вдруг если что, ещё можно в переменные функции и методы пихать...
как-то так...

Вот вам ссылочка на переводик
Ссылки на класс
https://pascal-study.blogspot.com/2012/ ... 9.html?m=1


Добавлено спустя 32 минуты 42 секунды:
RRYTY писал(а):Тогда так:

Код: Выделить всё

L:= TList(theClass.Create).Create;
Вам спасибо за интересный вариант
рабочий но спорный... В какойто момент думал распечатать повесить в рамку и в церьковь к экзорцистам бесов изгонять :twisted:
но после пояснений wavebvg и Alex2013 стало понятно как это работет...

и получается, что у себя я не смогу этим вариантов воспользоваться, т.к. эта "богадельня" по юнитам разным разбросана
  • 1. theClass.Create - выделит памяти для TObject (тут нет доступа к декларации, тип внутри переменной)
    2. в следующей функции if L.Count = 0 then L.Add(...);
    3. и только в следующей функции я буду иметь доступ к декларации TList-a и его наследников...
вся суть теряется

Добавлено спустя 9 минут 41 секунду:
wavebvg писал(а):
Всё зависит от менеджера памяти и включенных опций безопасности и т.п.

0. TObject.Create и TList.Create -- статические методы. Значит TList(theClass.Create); вызовет только TObject.Create выделит памяти для TObject.

1. TList(theClass.Create).Create; вызовет TObject.Create выделит памяти для TObject, после чего вызовет конструктор для TList.Create и попортит память за пределами класса.

2. В Дельфе TList класс в себе и ничего в конструкторе интересного не делает, в отличии от FPC-го, который, по сути, является делегированной обёрткой над TFPList.

3. Если обращение TFPList(nil).Count у Вас работает, т.е. чтение из адреса 0+Смещение FCount (+$10 судя из поста топикстартера) из TFPList, то нет AV, в противном случае есть.
Я считаю что это бага в FP
так как вся суть и прелесть использования Типа_ссылки_на_класс теряется

Добавлено спустя 16 минут 7 секунд:
Sharfik писал(а):
Юрий писал(а):>>Потому что Lazarus приличная IDE, а Delphi - нет. Delphi любит чтобы пользователь побольше мучался.
Тут я с вами не согласен. И та и та отличные среды, где-то в одной что-то удобнее, где-то в другой…
Тут вопрос выбора больше политически-идеологический… Моё личное мнение что после наступление примерного момента когда Убунта(и аналоги) стали по качеству луче чем Винда… Сначала Винда со своими обновлениями и инновациями пойдёт постепенно в Ж… А потом и Делфи потянется туда же… А для нас это процесс пойдёт быстрее, плоды начали всходить от санкций и импортозамещений…
При переходе с Delphi на Lazaasu о программировании узнаешь гораздо больше и код становится более продуманным.
Понятие "удобно" это путь к деградации. Вместо того чтобы учиться и изучать новое, люди упираются в одно какое то ПО и перестают развиваться. А дальше вместе с ними вся компания потенциально угасает. Сейчас это особенно заметно, когда люди вместо того чтобы попробовать что то новое начинают предлагать "давайте взломанный установим".
>>Понятие "удобно" это путь к деградации.
Что поделать деградация, регрессия, загнивание часть нашей жизни...
Ну вот иногда вам нужно забить гвоздь, вы идете в магаз и покупайте молоток, а можно купить и микроскоп, а можно купить завод, выплавить сталь и произвести молоток... У каждого своё "удобно"
Alex2013
долгожитель
Сообщения: 3211
Зарегистрирован: 03.04.2013 11:59:44

Сообщение Alex2013 »

Юрий писал(а):Я не понимаю степень вашей удивлённости.
Ну это как бы базовые вещи языка..., можно сказать "типизированный указатель", вдруг если что, ещё можно в переменные функции и методы пихать...
как-то так...
Ну и где вы там видели конструкцию "theClass := TList;"?
type TClass = class of TObject;
var AnyObj: TClass;
Это нормально . А var AnyObj: TClass; ... begin AnyObj := TObject;... ( или TList) нет .
Просто AnyObj у как был тип TClass так и остался . ( по моему там вообще ошибка вылезать должна)

Это же как если использовать нетипизированный параметры в процедуре/функции , "нетипизированный параметр" можно перевести к любому типу, но ПРИСВОИТЬ тип "в рунтайм режиме" по идее нельзя. :idea:


Если написать AnyObj := TObject.Create; то по сути язык просто глотает New и на самом деле делается AnyObj := New (TObject) и AnyObj.Create; написав AnyObj := TObject; мы не получаем ничего, возможно сработает New (TObject) но это очень сомнительно, а в случае AnyObj := TList; в fpc/лазарусе по умолчанию нужно написать приведение AnyObj := TClass (TList); В Дельфи куда более мягкое отношение к типизации по этому AnyObj := TList; может "проскочить" . Но даже так создать экземпляр класса БЕЗ вызова конструктора изрядная дикость .
Хм ! Возможно эта "лазейка" оставлена для использования классов "без конструктора но с деструктором" ( или возможности вызова "не стандартного" внешнего конструктора ) но все равно смотрится это очень бредово .
Юрий
новенький
Сообщения: 11
Зарегистрирован: 03.04.2022 02:32:16

Сообщение Юрий »

Alex2013 писал(а):
Юрий писал(а):Я не понимаю степень вашей удивлённости.
Ну это как бы базовые вещи языка..., можно сказать "типизированный указатель", вдруг если что, ещё можно в переменные функции и методы пихать...
как-то так...
Ну и где вы там видели конструкцию "theClass := TList;"?
type TClass = class of TObject;
var AnyObj: TClass;
Это нормально . А var AnyObj: TClass; ... begin AnyObj := TObject;... ( или TList) нет .
Просто AnyObj у как был тип TClass так и остался . ( по моему там вообще ошибка вылезать должна)

Это же как если использовать нетипизированный параметры в процедуре/функции , "нетипизированный параметр" можно перевести к любому типу, но ПРИСВОИТЬ тип "в рунтайм режиме" по идее нельзя. :idea:


Если написать AnyObj := TObject.Create; то по сути язык просто глотает New и на самом деле делается AnyObj := New (TObject) и AnyObj.Create; написав AnyObj := TObject; мы не получаем ничего, возможно сработает New (TObject) но это очень сомнительно, а в случае AnyObj := TList; в fpc/лазарусе по умолчанию нужно написать приведение AnyObj := TClass (TList); В Дельфи куда более мягкое отношение к типизации по этому AnyObj := TList; может "проскочить" . Но даже так создать экземпляр класса БЕЗ вызова конструктора изрядная дикость .
Хм ! Возможно эта "лазейка" оставлена для использования классов "без конструктора но с деструктором" ( или возможности вызова "не стандартного" внешнего конструктора ) но все равно смотрится это очень бредово .
>>Ну и где вы там видели конструкцию "theClass := TList;"?
CreateControl(TEdit, 'Edit1', 10, 10, 100, 20); // <-- здесь в стеке ControlClass : = TEdit


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

Как я думаю, это должно работать, если

Код: Выделить всё

type
  TAAA = class(TObject) …
  TBBB = class(TAAA)  …
  TCCC = class(TBBB)  …

  TClass = class of TObject;
то

Код: Выделить всё

var 
  theClass: TClass
begin
  theClass := TAAA;
  O := theClass.Create; // Создан экземпляр TAAA со своим переопределённым конструктором если он есть, не с констуктором TObject
  theClass := TBBB;
  O := theClass.Create; // Создан экземпляр TBBB со своим переопределённым конструктором
  theClass := TCCC;
  O := theClass.Create; // Создан экземпляр TCCC со своим переопределённым конструктором
И всё логично...
Ответить