Копия викизеркало

Это зеркало вики с pascal.chat. Правка, история и вход — там.

Avoiding implicit try finally section/ru

Bahasa Indonesia · English · Suomi · Русский

Обзор

Иногда полезно знать, что компилятор может обернуть код в неявный try ... finally блок. По сути дела это необходимо, когда вы используете переменную любого типа, которая должна быть инициализирована / деинициализирована (освобождена). Иными словами, стандартные процедуры Initialize() и Finalize() должны что-то сделать с ней. Это может быть актуально, например, при использовании переменных стандартных типов подобных AnsiStrings, Variants или динамических массивов.

Для примера, рассмотрим следующею процедуру:

pascal
procedure P;
var 
  S: AnsiString;
begin
  ... ???????????? ??????-???? ?? S ...
end;

Данная процедура, фактически компилируется как:

pascal
procedure P;
var 
  S: AnsiString;
begin
 Initialize(S);
 try
  ... ???????????? ??????-???? ?? S ...
 finally Finalize(S) end;
end;

Это необходимо, чтобы быть уверенным, что счетчик ссылок на переменную S, будет правильным, если процедура P завершится с ошибками. Однако, в некоторых случаях это может существенно повлиять на скорость данного кода.

Единственный правильный способ узнать, что происходит – просмотр вывода кода ассемблер.

Более подробную информацию, можете найти здесь: http://www.mail-archive.com/fpc-devel@lists.freepascal.org/msg01367.html

Возможные решения

Возможные риски

Warning: Используйте осторожно вызов данных исключений. Если вы оставите их без обработки, то возможны утечки памяти.

В 2007 году, директива $implicitexceptions была добавлена к модулю strutils. Если вы используете данный модуль, то обратите внимание на следующие нюансы:

Если вы обнаружили проблемы с этими изменениями, пожалуйста, свяжитесь с Marco.

Пример программы

Небольшая демонстрация программа, которая:

text
Время Foo_Normal: 141
Время Foo_Faster: 17
pascal
{$mode objfpc}{$H+}

uses
  {BaseUnix, Unix нужны только для реализации функции Clock} BaseUnix, Unix,
  SysUtils;

function Clock: Int64;
var Dummy: tms;
begin
 Clock := FpTimes(Dummy);
end;

procedure Foo_Normal(i: Integer);
var S: string;
begin
 if i = -1 then
 begin
  S := 'Некоторые операции с AnsiString';
  raise Exception.Create(S);
 end;
end;

procedure Foo_Faster(i: Integer);

  procedure RaiseError;
  var S: string;
  begin
   S := 'Некоторые операции с AnsiString';
   raise Exception.Create(S);
  end;

begin
 if i = -1 then RaiseError;
end;

{ Обратите внимание, что, когда я называю Foo_Normal и Foo_ResourceString
  i всегда >= 0 так что исключения никогда не происходит.
  Поэтому строковые константы SNormal и SResString не используется. }

const
  TestCount = 10000000;
var
  i: Integer;
  Start: Int64;
begin
 Start := Clock;
 for i := 0 to TestCount do Foo_Normal(i);
 Writeln('Время Foo_Normal: ', Clock - Start);

 Start := Clock;
 for i := 0 to TestCount do Foo_Faster(i);
 Writeln('Время Foo_Faster: ', Clock - Start);
end.

From the Free Pascal wiki, page "Avoiding implicit try finally section/ru", as it stood on 2020-02-09 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Версия 3, последнее изменение: WikiArchive, .