Вопрос с указателями на объекты

Общие вопросы программирования, алгоритмы и т.п.

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

Вопрос с указателями на объекты

Сообщение DeBRain » 25.07.2015 13:06:44

Вопрос кратко: почему в одном методе 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
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24

Re: Вопрос с указателями на объекты

Сообщение Лекс Айрин » 25.07.2015 13:29:25

DeBRain, может быть потому что она действительно не проинициализирована? И судя по вашему исходнику это так.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Вопрос с указателями на объекты

Сообщение DeBRain » 25.07.2015 13:37:31

Лекс Айрин Но ведь в первом случае она работает, хотя объявлена так же. Подскажите, что я упускаю.
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24

Re: Вопрос с указателями на объекты

Сообщение Лекс Айрин » 25.07.2015 13:45:02

Насколько я могу судить, ошибочна строчка

Код: Выделить всё
if Mode = ModeCreate then begin

Если у вас объект не создан, то как вы собираетесь Это проверить? Указатель же на него неопределен.

Добавлено спустя 51 секунду:
Точнее, не определено его значение.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Вопрос с указателями на объекты

Сообщение DeBRain » 25.07.2015 13:55:56

ModeCreate и ModeEdit - глобальные константы, определённые в том же umain.pas.
Mode - глобальная переменная, её значение задаётся в событии OnShow формы и меняется при нажатии на соответствующие кнопки на этой же форме.
В обоих фрагментах кода до строк tmpIdea^ := TIdea.Create; и Idea^ := TIdea.Create; доходит. Это проверенно. И код из файла uClasses.pas выполняется без проблем.

Указатель Idea^ объявлен в разделе VAR метода, и, как я думал, ему значение присваивается как раз в строчке Idea^ := TIdea.Create;.
То есть создаётся объект и ссылка на него записывается в указатель.
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24

Re: Вопрос с указателями на объекты

Сообщение Alexx2000 » 25.07.2015 14:19:05

У меня создается впечатление, что вы плохо понимаете как работать с указателями.
Код: Выделить всё
var
  Idea : ^TIdea;
begin
  if Mode = ModeCreate then begin
//    New(Idea); - с New работает как надо.
    Idea^ := TIdea.Create;

Разумеется данный код вызовет ошибку, вы разыменовываете неинициализированный указатель.
Аватара пользователя
Alexx2000
постоялец
 
Сообщения: 488
Зарегистрирован: 25.10.2006 00:22:07
Откуда: Мытищи

Re: Вопрос с указателями на объекты

Сообщение DeBRain » 25.07.2015 14:44:37

Согласен, работа с указателями мне не совсем ясна. Однако всё же почему в первом куске кода та же запись не вызывает у компилятора никаких сомнений и работает правильно, а второй - вызывает ошибку? Чем отличаются эти два случая?

Я не вижу различия между этими двумя случаями: по идее в обоих случаях я разыменовываю неинициализированный указатель.
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24

Re: Вопрос с указателями на объекты

Сообщение Alexx2000 » 25.07.2015 14:57:29

DeBRain писал(а):Я не вижу различия между этими двумя случаями: по идее в обоих случаях я разыменовываю неинициализированный указатель.

Верно, однако тут как повезет. Все зависит от того куда указывает ненициализированный указатель, в одном случае он может указывать в пустую область памяти, в итоге запись в него ничего не повредит сразу (однако программа может упасть через некоторое время, когда туда запишется что-то другое). Во втором случае указатель указывает на область памяти, уже занятую чем-то важным, в итоге падение происходит сразу. Таким образом данный код может привести к падению как сразу, так и через некоторое время.
Аватара пользователя
Alexx2000
постоялец
 
Сообщения: 488
Зарегистрирован: 25.10.2006 00:22:07
Откуда: Мытищи

Re: Вопрос с указателями на объекты

Сообщение Лекс Айрин » 25.07.2015 15:23:03

DeBRain писал(а):ModeCreate и ModeEdit - глобальные константы, определённые в том же umain.pas.
Mode - глобальная переменная, её значение задаётся в событии OnShow формы и меняется при нажатии на соответствующие кнопки на этой же форме.


вы бы привели весь код... а то, допустим, мне ничего не говорит то, что они глобальны. Мы тут даже не знаем как определен объект

Добавлено спустя 14 минут 51 секунду:
Ну да... наконец-то нашел справку... вы совершенно зря не используете new. Из-за этого у вас указатель смотрит неизвестно куда. Если по какой-то причине нежелательно, то используйте GetMem/SetMem.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Вопрос с указателями на объекты

Сообщение DeBRain » 25.07.2015 15:37:56

вы бы привели весь код... а то, допустим, мне ничего не говорит то, что они глобальны. Мы тут даже не знаем как определен объект

Полные версии
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.
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24

Re: Вопрос с указателями на объекты

Сообщение zub » 26.07.2015 00:13:48

Оба варианта неверные. То что один работает - просто везение которое закончится или через неделю или на другом компьютере))
>>Вопрос с указателями на объекты
Как уже заметтли вы разименовыаете неинициализированный указатель. На лицо применение "старых" методов работы которые были применимы к object`ам к "современным" class`ам... Не то что бы так делать нельзя, но это явно от непонимания - класс уже указатель, делать указатель на класс без необходимости нестоит.
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопрос с указателями на объекты

Сообщение DeBRain » 26.07.2015 04:07:11

zub, хорошо, спасибо за прояснение. :)
DeBRain
незнакомец
 
Сообщения: 7
Зарегистрирован: 30.01.2015 08:41:24


Вернуться в Общее

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

Рейтинг@Mail.ru