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

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

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

Ответить
Аватара пользователя
Cheb
энтузиаст
Сообщения: 994
Зарегистрирован: 06.06.2005 15:54:34
Контактная информация:

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

Сообщение Cheb »

Прикольная фича, я раньше не имел дела и не знал, а, оказывается, передача непустой переменной типа с подсчётом ссылок (строки, массивы) в функцию как 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.
скалогрыз
долгожитель
Сообщения: 1804
Зарегистрирован: 03.09.2008 02:36:48

Сообщение скалогрыз »

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;
MrShoor
незнакомец
Сообщения: 1
Зарегистрирован: 01.11.2016 07:32:10

Сообщение MrShoor »

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

Ага, я вот тут описывал как ARC переменные работают, при передачи их параметрами (первая задачка и там ответ на неё ниже): https://habrahabr.ru/post/269359/
Ответить