Sign in Join
Wiki copytemporary

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.

Revision 3, last changed by WikiArchive .

Edited on wiki.freepascal.org by 2 people, 2016–2020

From the official wiki's backup of 26 May 2024: who edited this page there, and when. Edits made there after that date were not recorded, and the earlier versions are not shown here; the main page says why.

WhenWhoWhat changed
AmberCreated page
Amber
Amber
TrevFixed syntax highlighting; deleted category already in page template (minor)

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.