Страница 1 из 1
Вопрос с указателями на объекты
Добавлено:
25.07.2015 13:06:44
DeBRain
Вопрос кратко: почему в одном методе
tmpIdea^ := TIdea.Create; работает нормально, а в другом
Idea^ := TIdea.Create; - говорит что переменная не проинициализирована и выдаёт ошибку во время выполнения программы:
Проект Ideas вызвал класс исключения 'SIGSEGV'. В файле umain.pas на строке 74: Idea^ := TIdea.Create;"
?
Файл uClasses.pas- Код: Выделить всё
function TIdeasList.LoadIdeasList: Boolean;
var
tmpIdea : ^TIdea;
begin
with DB_DataModule do begin
if not MySQL56Connection1.Connected then MySQL56Connection1.Open;
if MySQL56Connection1.Connected then begin
SQLQuery1.Close;
SQLQuery1.SQL.Text:= 'SELECT `id`, `title` FROM `ideas`;';
SQLQuery1.Open;
IdeasListViewer^.BeginUpdate;
IdeasListViewer^.Clear;
while not SQLQuery1.EOF do begin
tmpIdea^ := TIdea.Create;
tmpIdea^.ID:= SQLQuery1.FieldByName('ID').AsLongint;
tmpIdea^.Title:= SQLQuery1.FieldByName('title').AsString;
IdeasListViewer^.AddItem(tmpIdea^.Title, nil);
IdeasListViewer^.Items.Item[IdeasListViewer^.Items.Count-1].Data := tmpIdea;
SQLQuery1.Next;
end;
SQLQuery1.Close;
IdeasListViewer^.EndUpdate;
end;
end;
Result := true;
end;
Файл umain.pas- Код: Выделить всё
procedure TForm1.OKBBClick(Sender: TObject);
var
Idea : ^TIdea;
begin
if Mode = ModeCreate then begin
// New(Idea); - с New работает как надо.
Idea^ := TIdea.Create;
Idea^.Title:= TitleLE.Text;
Idea^.Description:= DescriptionM.Text;
IdeasList.AddNewIdea(Idea);
Idea^.Save;
end
else
if ListView1.SelCount = 1 then begin
Idea := ListView1.Selected.Data;
Idea^.Title:= TitleLE.Text;
Idea^.Description:= DescriptionM.Text;
Idea^.Save;
end;
end;
Версия Lazarus 1.4.2
Версия FPC 2.6.4
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 13:29:25
Лекс Айрин
DeBRain, может быть потому что она действительно не проинициализирована? И судя по вашему исходнику это так.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 13:37:31
DeBRain
Лекс Айрин Но ведь в первом случае она работает, хотя объявлена так же. Подскажите, что я упускаю.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 13:45:02
Лекс Айрин
Насколько я могу судить, ошибочна строчка
- Код: Выделить всё
if Mode = ModeCreate then begin
Если у вас объект не создан, то как вы собираетесь Это проверить? Указатель же на него неопределен.
Добавлено спустя 51 секунду:Точнее, не определено его значение.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 13:55:56
DeBRain
ModeCreate и ModeEdit - глобальные константы, определённые в том же umain.pas.
Mode - глобальная переменная, её значение задаётся в событии OnShow формы и меняется при нажатии на соответствующие кнопки на этой же форме.
В обоих фрагментах кода до строк tmpIdea^ := TIdea.Create; и Idea^ := TIdea.Create; доходит. Это проверенно. И код из файла uClasses.pas выполняется без проблем.
Указатель Idea^ объявлен в разделе VAR метода, и, как я думал, ему значение присваивается как раз в строчке Idea^ := TIdea.Create;.
То есть создаётся объект и ссылка на него записывается в указатель.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 14:19:05
Alexx2000
У меня создается впечатление, что вы плохо понимаете как работать с указателями.
- Код: Выделить всё
var
Idea : ^TIdea;
begin
if Mode = ModeCreate then begin
// New(Idea); - с New работает как надо.
Idea^ := TIdea.Create;
Разумеется данный код вызовет ошибку, вы разыменовываете неинициализированный указатель.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 14:44:37
DeBRain
Согласен, работа с указателями мне не совсем ясна. Однако всё же почему в первом куске кода та же запись не вызывает у компилятора никаких сомнений и работает правильно, а второй - вызывает ошибку? Чем отличаются эти два случая?
Я не вижу различия между этими двумя случаями: по идее в обоих случаях я разыменовываю неинициализированный указатель.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 14:57:29
Alexx2000
DeBRain писал(а):Я не вижу различия между этими двумя случаями: по идее в обоих случаях я разыменовываю неинициализированный указатель.
Верно, однако тут как повезет. Все зависит от того куда указывает ненициализированный указатель, в одном случае он может указывать в пустую область памяти, в итоге запись в него ничего не повредит сразу (однако программа может упасть через некоторое время, когда туда запишется что-то другое). Во втором случае указатель указывает на область памяти, уже занятую чем-то важным, в итоге падение происходит сразу. Таким образом данный код может привести к падению как сразу, так и через некоторое время.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 15:23:03
Лекс Айрин
DeBRain писал(а):ModeCreate и ModeEdit - глобальные константы, определённые в том же umain.pas.
Mode - глобальная переменная, её значение задаётся в событии OnShow формы и меняется при нажатии на соответствующие кнопки на этой же форме.
вы бы привели весь код... а то, допустим, мне ничего не говорит то, что они глобальны. Мы тут даже не знаем как определен объект
Добавлено спустя 14 минут 51 секунду:Ну да... наконец-то нашел справку... вы совершенно зря не используете new. Из-за этого у вас указатель смотрит неизвестно куда. Если по какой-то причине нежелательно, то используйте GetMem/SetMem.
Re: Вопрос с указателями на объекты
Добавлено:
25.07.2015 15:37:56
DeBRain
вы бы привели весь код... а то, допустим, мне ничего не говорит то, что они глобальны. Мы тут даже не знаем как определен объект
Полные версии
umain.pas- Код: Выделить всё
unit uMain;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
ComCtrls, StdCtrls, Buttons, ActnList, uClasses;
type
{ TForm1 }
TForm1 = class(TForm)
ClearIdeaDetaisFieldsA: TAction;
ActionList1: TActionList;
OKBB: TBitBtn;
BitBtn2: TBitBtn;
CreateBB: TBitBtn;
Label1: TLabel;
TitleLE: TLabeledEdit;
ListView1: TListView;
DescriptionM: TMemo;
Panel1: TPanel;
Panel2: TPanel;
procedure OKBBClick(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure ClearIdeaDetaisFieldsAExecute(Sender: TObject);
procedure CreateBBClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure ListView1Click(Sender: TObject);
procedure ListView1Deletion(Sender: TObject; Item: TListItem);
private
{ private declarations }
public
{ public declarations }
end;
const
ModeEdit = false;
ModeCreate = true;
var
Form1: TForm1;
IdeasList : TIdeasList;
Mode : Boolean;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormShow(Sender: TObject);
begin
IdeasList := TIdeasList.Create(@ListView1);
IdeasList.LoadIdeasList();
ClearIdeaDetaisFieldsA.Execute;
end;
procedure TForm1.CreateBBClick(Sender: TObject);
begin
ClearIdeaDetaisFieldsA.Execute;
end;
procedure TForm1.OKBBClick(Sender: TObject);
var
Idea : ^TIdea;
begin
if Mode = ModeCreate then begin
// New(Idea);
Idea^ := TIdea.Create;
Idea^.Title:= TitleLE.Text;
Idea^.Description:= DescriptionM.Text;
IdeasList.AddNewIdea(Idea);
Idea^.Save;
end
else
if ListView1.SelCount = 1 then begin
Idea := ListView1.Selected.Data;
Idea^.Title:= TitleLE.Text;
Idea^.Description:= DescriptionM.Text;
Idea^.Save;
end;
end;
procedure TForm1.BitBtn2Click(Sender: TObject);
begin
if ListView1.SelCount = 1 then begin
//событие по клику мыши на элементе списка
end
else begin
//очистка формы
end;
end;
procedure TForm1.ClearIdeaDetaisFieldsAExecute(Sender: TObject);
begin
if ListView1.SelCount > 0 then ListView1.Selected.Selected:=false;
TitleLE.Text:='';
DescriptionM.Text:='';
Mode:= ModeCreate;
end;
procedure TForm1.ListView1Click(Sender: TObject);
var
Idea : ^TIdea;
begin
if (ListView1.SelCount = 1) then begin
Idea := ListView1.Selected.Data;
Idea^.LoadIdeaDetails;
TitleLE.Text:= Idea^.Title;
DescriptionM.Text:= Idea^.Description;
Mode:=ModeEdit;
end;
end;
procedure TForm1.ListView1Deletion(Sender: TObject; Item: TListItem);
var
Idea : ^TIdea;
begin
try
Idea := Item.Data;
Idea^.Free;
except
MessageDlg('asdfasdf', mtConfirmation,[mbOK],-1);
end;
end;
end.
uClasses.pas- Код: Выделить всё
unit uClasses;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, uDBComponents, ComCtrls;
type
PTListView = ^TListView;
PTIdea = ^TIdea;
{ TIdeasList }
TIdeasList = class
public
IdeasListViewer : PTListView;
constructor Create(IListViewer : PTListView);
function LoadIdeasList : Boolean;
procedure AddNewIdea( Idea : PTIdea );
end;
TIdea = class
private
ID : Cardinal;
public
Title : String;
Description : String;
constructor Create;
function GetID : Cardinal;
procedure LoadIdeaDetails;
procedure Save;
end;
implementation
{ TIdea }
constructor TIdea.Create;
begin
inherited Create;
ID := 0;
end;
function TIdea.GetID: Cardinal;
begin
Result := ID;
end;
procedure TIdea.LoadIdeaDetails;
begin
with DB_DataModule do begin
if not MySQL56Connection1.Connected then MySQL56Connection1.Open;
if MySQL56Connection1.Connected then begin
SQLQuery1.Close;
SQLQuery1.SQL.Text := 'SELECT `description` FROM `ideas` WHERE `id` = ' + IntToStr(ID)+';';
SQLQuery1.Open;
Description:=SQLQuery1.FieldByName('description').AsString;
SQLQuery1.Close;
end;
end;
end;
procedure TIdea.Save;
var
Query : string;
begin
with DB_DataModule do begin
if not MySQL56Connection1.Connected then MySQL56Connection1.Open;
if MySQL56Connection1.Connected then begin
//формируем запрос
if ID <> 0
then Query := 'UPDATE `ideas` SET `title` = '
+ #39 + Title + #39 +
', `description` = '
+ #39 + Description + #39 +
' where id = ' + IntToStr(ID) +';'
else Query := 'INSERT INTO `ideas` (`title`, `description`) VALUES ('
+ #39 + Title + #39 + ', '
+ #39 + Description + #39 + ');';
//выполняем запрос
SQLQuery1.Close;
SQLQuery1.SQL.Text:= Query;
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
//SQLQuery1.RowsAffected;
SQLQuery1.Close;
end;
end;
end;
{ TIdeasList }
constructor TIdeasList.Create(IListViewer: PTListView);
begin
IdeasListViewer:= iListViewer;
end;
function TIdeasList.LoadIdeasList: Boolean;
var
tmpIdea : ^TIdea;
begin
with DB_DataModule do begin
if not MySQL56Connection1.Connected then MySQL56Connection1.Open;
if MySQL56Connection1.Connected then begin
SQLQuery1.Close;
SQLQuery1.SQL.Text:= 'SELECT `id`, `title` FROM `ideas`;';
SQLQuery1.Open;
IdeasListViewer^.BeginUpdate;
IdeasListViewer^.Clear;
while not SQLQuery1.EOF do begin
tmpIdea^ := TIdea.Create;
tmpIdea^.ID:= SQLQuery1.FieldByName('ID').AsLongint;
tmpIdea^.Title:= SQLQuery1.FieldByName('title').AsString;
IdeasListViewer^.AddItem(tmpIdea^.Title, nil);
IdeasListViewer^.Items.Item[IdeasListViewer^.Items.Count-1].Data := tmpIdea;
SQLQuery1.Next;
end;
SQLQuery1.Close;
IdeasListViewer^.EndUpdate;
end;
end;
Result := true;
end;
procedure TIdeasList.AddNewIdea(Idea: PTIdea);
begin
IdeasListViewer^.AddItem(Idea^.Title, nil);
IdeasListViewer^.Items[IdeasListViewer^.Items.Count-1].Data:= Idea;
end;
end.
Re: Вопрос с указателями на объекты
Добавлено:
26.07.2015 00:13:48
zub
Оба варианта неверные. То что один работает - просто везение которое закончится или через неделю или на другом компьютере))
>>Вопрос с указателями на объекты
Как уже заметтли вы разименовыаете неинициализированный указатель. На лицо применение "старых" методов работы которые были применимы к object`ам к "современным" class`ам... Не то что бы так делать нельзя, но это явно от непонимания - класс уже указатель, делать указатель на класс без необходимости нестоит.
Re: Вопрос с указателями на объекты
Добавлено:
26.07.2015 04:07:11
DeBRain
zub, хорошо, спасибо за прояснение.