Ошибка в операции сравнения logfile<>StdOut

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

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

Ошибка в операции сравнения logfile<>StdOut

Сообщение VshMt! » 30.04.2020 01:52:49

ДВС всем!

На старости лет решил тряхнуть таки и вспомнить прелести. Установил себе на старинный бук линух и лазарус. Решил накидать некий интерактивный макетик проги. Руки с трудом вспоминают то что мозги вже забыли. делаю логер. Если есть имя файла - открываю на запись, а если нет - беру stdout
Код: Выделить всё
constructor TMyLogger.Create(fn: string);
begin
  if fn <> '' then
    begin
      Assign(logfile_,fn);
      {i-}
      Rewrite(logfile_);
      {i+}
      if IOResult<>0 then ;// Ошибка IOResult
    end
  else logfile_ := stdout;
end;

Ну и в деструкторе
Код: Выделить всё
destructor TMyLogger.Destroy;
begin
  if logfile_ <> StdOut
    then Close(logfile_)
    else Flush(logfile_);
end;

Ругается на деструкто, а именно на

Код: Выделить всё
  if logfile_ <> StdOut


Код: Выделить всё
Компиляция проекта, цель: project1: Код завершения 1, ошибок: 2, предупреждений: 1
states.pas(21,16) Warning: An inherited method is hidden by "destructor Destroy;"
states.pas(67,6) Error: Incompatible types: got "Text" expected "LongInt"
states.pas(67,18) Error: Incompatible types: got "Text" expected "LongInt"


Я не очень понял почему так нельзя? Обе переменные типа Text...
VshMt!
незнакомец
 
Сообщения: 3
Зарегистрирован: 30.04.2020 01:31:09

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение Дож » 06.05.2020 05:39:03

1. Ошибка действительно странная и неинформативная.

2. Тем не менее, сомневаюсь, что для текстовых файлов предусмотрена и определена операция сравнения. Она описана где-то в документации? Тот же вопрос про операцию присваивания.

Один из способов обойти это -- добавить в программу переменную-указатель T: PText, которая будет ссылаться либо на logfile_ (буферная переменная), либо на StdOut. Тогда сранвние T <> @StdOut будет заведомо корректным.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 854
Зарегистрирован: 12.10.2008 16:14:47

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение Снег Север » 06.05.2020 09:57:16

Где и как описана переменная logfile_ ?

Для копирования файловых дескрипторов служит функция FpDup(oldfile,newfile).
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2637
Зарегистрирован: 27.11.2007 16:14:47

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение VshMt! » 12.05.2020 12:12:03

Всем привет и поздравления с прошедшим Праздником! Давно не заходил поэтому поздно отвечаю. Спасибо за разъяснение буду проверять. Но думаю что вы правы. Еще раз спасибо.

Добавлено спустя 7 минут 32 секунды:
И да. Забыл.

Код: Выделить всё
logfile_: Text;
VshMt!
незнакомец
 
Сообщения: 3
Зарегистрирован: 30.04.2020 01:31:09

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение Снег Север » 12.05.2020 13:00:58

Дож верно написал, для файловых переменных сравнение не определено. Но можно сравнивать и присваивать дескрипторы файлов, которые эквивалентны целым числам.
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2637
Зарегистрирован: 27.11.2007 16:14:47

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение runewalsh » 12.05.2020 14:20:56

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

Скорее всего, так делать нельзя, т. к. будут возникать конфликты при записи в stdout через обе переменные — например, помимо всего прочего text-переменная содержит БУФЕР и позицию в нём (см. TTextRec), и после logfile_ := stdout возникают 2 рассинхронизированные копии этого состояния.

Можно вот так:
Код: Выделить всё
type
    TMyLogger = class
        ...
        logFile: PText;
        ownedLogFile: Text;
        ...
        destructor TMyLogger.Destroy; override;
    end;

    constructor TMyLogger.Create(const fn: string);
    begin
        if fn <> '' then
        begin
            Assign(ownedLogFile, fn); {i-} Rewrite(ownedLogFile); {i+}
            if IOResult<>0 then ;// Ошибка IOResult
            logFile := @ownedLogFile;
        end else
            logFile := @stdout;
    end;

    destructor TMyLogger.Destroy;
    begin
        if logFile <> nil then
            if logFile = @ownedLogFile then Close(logFile^) else Flush(logFile^);
    end;


И для вывода работать с logFile^.

— Допиши в объявлении класса override к деструктору (как в моём примере), т. к. деструктор — виртуальный метод. Иначе, во-первых, компилятор недоволен, во-вторых, если ты будешь работать со своим TMyLogger через предка (TObject) и через него же вызовешь деструктор, то вызовется деструктор TObject'а, а с override — деструктор настоящего типа, т. е. TMyLogger'а. (Потому и недоволен.) «Работа через предка (TObject)» — это в том числе вызов Free!

— Если из конструктора будет брошено исключение (например, ты можешь захотеть его бросить в ответ на неудавшееся создание файла), будет выполнен деструктор, поэтому деструктор должен уметь работать с недоконструированным объектом, часть полей которого занулены.

— Передавай строки (и остальные managed-типы) через const. Передача без квалификатора понапрасну дёргает счётчик ссылок (это 2 атомарные инструкции), а через const — бесплатна. (Здесь приведён пример кода, который меняет поведение при передаче по const, но в реальности так никто никогда не делает, я надеюсь.)
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 471
Зарегистрирован: 27.04.2010 00:15:25

Re: Ошибка в операции сравнения logfile<>StdOut

Сообщение VshMt! » 13.05.2020 11:35:37

ДВС! Спасибо всем поучавствовавшим. Все фунциклирует.
VshMt!
незнакомец
 
Сообщения: 3
Зарегистрирован: 30.04.2020 01:31:09


Вернуться в Lazarus

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

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

Рейтинг@Mail.ru