Delphi - сбориник статей

       

Коварные Warnings


Предупреждения-warnings обладают гораздо более высоким уровнем опасности с точки зрения компилятора. История с абстрактным классом служит тому примером. Разберем еще несколько случаев возникновения warning'ов: Return value of function 'VarCompare' might be undefined Значение результата функции 'VarCompare' может быть неопределено.

Function VarCompare(Index1, Index2: Integer): Integer; Begin IF Index1 = Index2 Then Result:=0; IF Index1 < Index2 Then Result:=-1; IF Index1 > Index2 Then Result:=1; End; ‹——Return value of function 'VarCompare' might be undefined

Казалось бы, с точки зрения логики в тексте функции все верно. Перекрыты все возможные случаи и сообщение компилятора выглядит несколько неуместно. Но не стоит ждать от него слишком много, компилятор не может (да и не обязан) вникать в логику программы. Для того, чтобы избавиться от этого сообщения, было бы правильно переписать это код. Например, вот так:

Function VarCompare(Index1, Index2: Integer): Integer; Begin IF Index1 = Index2 Then Result:=0 Else IF Index1 < Index2 Then Result:=-1 Else Result:=1; End;

В итоге и компилятор "отстанет", и код будет более читабельным. Это сообщение только на первый взгляд кажется безобидным, ниже приведен пример, в котором возникает аналогичное предупреждение и содержится реальная ошибка — если возникнет исключительная ситуация при открытии файла, результат функции, действительно, не будет определен. В итоге это скажется при выполнении программы, когда ошибки никто не будет ожидать.



Function ReadList( FileName : String) : Boolean ; Var Stream : TFileStream; Begin IF FileExists(FileName) Then Try Stream:=TFileStream.Create(FileName , fmOpenRead); // ..... Stream.Free; Result:=True; Except End Else Result:=False; End;‹——Return value of function 'ReadList' might be undefined
Правильный вариант:

Function ReadList( FileName : String) : Boolean ; Var Stream : TFileStream; Begin IF FileExists(FileName) Then Try Stream:=TFileStream.Create(FileName , fmOpenRead); // ..... Stream.Free; Result:=True; Except Result:=False; End Else Result:=False; End;
Еще один пример коварного warning'а: Variable 'list' might not have been initialized Переменная 'list' может быть не инициализирована.

Function SomethingList( Text : String) : Integer; Var list : TStringList; Begin IF Text <> '' Then Begin list:=TStringList.Create; list.CommaText:=Text; End; // .... код Result:=list.Count; ‹—— Variable 'list' might not have been initialized list.Free; End;

Совершенно справедливое замечание. Если во время работы программы в функцию будет передана пустая строка, нам обеспечен знаменитый Access violation.
Вернемся еще раз к примеру с определением собственных классов.

TExLists = class(TList) Public procedure Clear; ‹—— Method 'Clear' hides virtual method of base type 'TList' End;
Method 'Clear' hides virtual method of base type 'TList' Метод 'Clear' прячет виртуальный метод базового класса 'TList'. Эта ситуация буквально означает перекрытие виртуального метода родительского класса. То есть, в классе TExLists определен статический метод, имя которого совпадает с виртуальным методом родительского класса TList. Если в дальнейшем, от класса TExLists будут наследоваться, то метод Clear для этих наследников будет закрыт. Правильный вариант:

TExLists = class(TList) Public procedure Clear; override; End;

Точно также, как и в случае с hint'ами, существуют опции для отключения сообщений компилятора о предупреждениях — {$WARNINGS OFF}, и для их включения — {$WARNINGS ON}. И точно так же хочу обратить внимание на нежелательность использования этих опций без нужды. Молчание компилятора в этом случае не будет означать отсутствие проблемы :о)



Содержание раздела