Оказывается, передача ref-counted как out деспавнит его

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Оказывается, передача ref-counted как out деспавнит его

Сообщение Cheb » 30.10.2016 20:55:54

Прикольная фича, я раньше не имел дела и не знал, а, оказывается, передача непустой переменной типа с подсчётом ссылок (строки, массивы) в функцию как out параметра (который подобен var параметру, только out) приводит к очистке этой переменной до вызова (точнее, до того, как начнёт выполняться тело функции). Если при этом счётчик ссылок обнулится, то refcounted сущность, естественно, деспавнится.

Цельнотяг-с
, приспособил тест к фпц под винду, для полноценности надо ещё заменить на {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
Код: Выделить всё
// https://pascal.today/2016/08/17/const-parameters-vs-non-const/
{$mode objfpc}

program ParameterTypes;

{$APPTYPE CONSOLE}

type
  ITest = interface
    ['{D200C91B-3D4D-45AB-A1E0-A803C6A03292}']
  end;

TTest = class(TInterfacedObject, ITest)
private
   function _AddRef: Integer; stdcall;
   function _Release: Integer; stdcall;
end;

function TTest._AddRef: Integer; stdcall;
begin
Writeln(FRefCount + 1);
Result := inherited;
end;

function TTest._Release: Integer; stdcall;
begin
Writeln(FRefCount - 1);
Result := inherited;
end;

procedure TestStandard(X: ITest);
begin
Writeln('Inside standard');
end;

procedure TestVar(var X: ITest);
begin
Writeln('Inside var');
end;

procedure TestConst(const X: ITest);
begin
Writeln('Inside const');
end;

{procedure TestConstRef(const [Ref] X: ITest);
begin
Writeln('Inside const');
end;
}

procedure TestOut(out X: ITest);
begin
Writeln('Inside out');
end;

var
  X: ITest;
begin
  Writeln(StringOfChar('-', 40));
  Writeln('Creating and calling with standard parameter type:');
  X := TTest.Create;
  TestStandard(X);
  X := nil;
  Writeln(StringOfChar('-', 40));

  Writeln('Creating and calling with var parameter type:');
  X := TTest.Create;
  TestVar(X);
  X := nil;
  Writeln(StringOfChar('-', 40));

  Writeln('Creating and calling with const parameter type:');
  X := TTest.Create;
  TestConst(X);
  X := nil;
  Writeln(StringOfChar('-', 40));
{
  Writeln('Creating and calling with const [Ref] parameter type:');
  X := TTest.Create;
  TestConstRef(X);
  X := nil;
  Writeln(StringOfChar('-', 40));
}
  Writeln('Creating and calling with out parameter type:');
  X := TTest.Create;
  TestOut(X);
  X := nil;
  Writeln(StringOfChar('-', 40));

  Readln;
end.
Аватара пользователя
Cheb
энтузиаст
 
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34

Re: Оказывается, передача ref-counted как out деспавнит его

Сообщение скалогрыз » 30.10.2016 21:19:49

Cheb писал(а):Прикольная фича, я раньше не имел дела и не знал, а, оказывается, передача непустой переменной типа с подсчётом ссылок (строки, массивы) в функцию как out параметра (который подобен var параметру, только out) приводит к очистке этой переменной до вызова (точнее, до того, как начнёт выполняться тело функции). Если при этом счётчик ссылок обнулится, то refcounted сущность, естественно, деспавнится.

как видишь он не просто "подобен var параметру, только out".

Функционал описан в документации: "the initial value of the parameter on function entry is discarded, and should not be used.
...
Remark: For managed types (reference counted types), using Out parameters incurs some overhead: the compiler must be sure that the value is correctly initialized (i.e. has a reference count of zero (0)). This initialization is normally done by the caller"

Как вариант ты можешь просто не указывать тип параметра (аля QueryInterface):
Код: Выделить всё
procedure TestOut(out X);
begin
Writeln('Inside out');
end;
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Оказывается, передача ref-counted как out деспавнит его

Сообщение MrShoor » 01.11.2016 08:35:47

Cheb писал(а):Прикольная фича, я раньше не имел дела и не знал, а, оказывается, передача непустой переменной типа с подсчётом ссылок (строки, массивы) в функцию как out параметра (который подобен var параметру, только out) приводит к очистке этой переменной до вызова (точнее, до того, как начнёт выполняться тело функции). Если при этом счётчик ссылок обнулится, то refcounted сущность, естественно, деспавнится.

Ага, я вот тут описывал как ARC переменные работают, при передачи их параметрами (первая задачка и там ответ на неё ниже): https://habrahabr.ru/post/269359/
MrShoor
незнакомец
 
Сообщения: 1
Зарегистрирован: 01.11.2016 08:32:10


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru