На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Rouse_, jack128, Krid
  
    > auto_ptr в Delphi , D2009+
      Плюсовый шаблон auto_ptr одна из тех фишек, которых на мой скромный взгляд очень не хватает в Delphi.
      В некоторой степени приближения, я попытался изобразить его аналог с помощью средств последних версий языка в Delphi. Получилось следующее (интерфейс по сути общий, но с реализаций пока только для классов, но под другие ресурсы добавить поддержку не составит трудов):
      ExpandedWrap disabled
        unit AutoPtr;
         
        interface
         
        type
          auto_ptr<TResource> = interface
            function is_empty(): Boolean;
            function get(): TResource;
            function release(): TResource;
            procedure reset(ToAnother: TResource);
            property Empty: Boolean read is_empty;
            property Obj: TResource read get;
          end;
         
          TObjectContainer<TClass: class> = class(TInterfacedObject, auto_ptr<TClass>)
          strict private
            FObject: TClass;
          public
            constructor Create(Obj: TClass);
            destructor Destroy(); override;
            function is_empty(): Boolean; inline;
            function get(): TClass; inline;
            function release(): TClass; inline;
            procedure reset(ToAnother: TClass);
          end;
         
          auto_class_ptr<TClass: class> = record
            Container: TObjectContainer<TClass>;
            class operator Explicit(Obj: TClass): auto_class_ptr<TClass>; inline;
            class operator Implicit(Tmp: auto_class_ptr<TClass>): auto_ptr<TClass>; inline;
          end;
         
        implementation
         
        { TObjContainer<TClass> }
         
        constructor TObjectContainer<TClass>.Create(Obj: TClass);
        begin
          inherited Create();
          FObject := Obj;
        end;
         
        destructor TObjectContainer<TClass>.Destroy();
        begin
          FObject.Free();
          inherited Destroy();
        end;
         
        function TObjectContainer<TClass>.is_empty(): Boolean;
        begin
          Result := (FObject = nil);
        end;
         
        function TObjectContainer<TClass>.get(): TClass;
        begin
          Result := FObject;
        end;
         
        function TObjectContainer<TClass>.release(): TClass;
        begin
          Result := FObject;
          FObject := nil;
        end;
         
        procedure TObjectContainer<TClass>.reset(ToAnother: TClass);
        var
          Old: TClass;
        begin
          Old := FObject;
          if (ToAnother <> Old) then
          begin
            FObject := ToAnother;
            Old.Free();
          end;
        end;
         
        { auto_class_ptr<TClass> }
         
        class operator auto_class_ptr<TClass>.Explicit(Obj: TClass): auto_class_ptr<TClass>;
        var
          Tmp: auto_class_ptr<TClass>;
        begin
          Tmp.Container := TObjectContainer<TClass>.Create(Obj);
          Result := Tmp;
        end;
         
        class operator auto_class_ptr<TClass>.Implicit(Tmp: auto_class_ptr<TClass>): auto_ptr<TClass>;
        begin
          Result := Tmp.Container;
        end;
         
        end.

      Тип-запись auto_class_ptr не обязателен на самом деле, а служит лишь для лаконичности и удобности кодирования и чтения на мой вкус. Можно обойтись без него.

      Итак, зачем это нужно. Механизм призван заменить конструкции в коде вида:
      ExpandedWrap disabled
        procedure TForm1.ButtonClick(Sender: TObject);
        var
          Strings: TStrings;
        begin
          Strings := TStringList.Create();
          try
            Strings.LoadFromFile('.\TestFile.txt');
            if (Strings.Count > 0) then
              Self.Caption := Format('Got %d line(s) in file', [Strings.Count])
            else
              Self.Caption := 'File is empty';
          finally
            Strings.Free();
          end;
        end;

      На укороченные, но также гарантирующие освобождение ресурсов:
      ExpandedWrap disabled
        procedure TForm1.ButtonClick(Sender: TObject);
        var
          Strings: auto_ptr<TStrings>;
        begin
          Strings := auto_class_ptr<TStrings>(TStringList.Create());
          Strings.Obj.LoadFromFile('.\TestFile.txt');
          if (Strings.Obj.Count > 0) then
            Self.Caption := Format('Got %d line(s) in file', [Strings.Obj.Count])
          else
            Self.Caption := 'File is empty';
        end;

      Без использования auto_class_ptr это выглядит так:
      ExpandedWrap disabled
        procedure TForm1.Button4Click(Sender: TObject);
        var
          Strings: auto_ptr<TStrings>;
        begin
          Strings := TObjectContainer<TStrings>.Create(TStringList.Create());//просто непосредственное создание объекта-оболочки
          Strings.Obj.LoadFromFile('.\TestFile.txt');
          if (Strings.Obj.Count > 0) then
            Self.Caption := Format('Got %d line(s) in file', [Strings.Obj.Count])
          else
            Self.Caption := 'File is empty';
        end;

      Каков выигрыш: в представленном простейшем случае экономия 4 строки по вертикали и 1 уровень отступов по горизонтали на основной рабочий код. И это в простейшем случае, а чем сложнее (вложенные или просто последовательные получения ресурсов), тем больше.
      А за краткость методов я борюсь и для меня это важно.
      Насчет выигрыша по горизонтали
      Да, выигрыш по горизонтали несколько сомнителен, т.к. требуется дополнительные символы ".Obj", но
      • лично для меня важнее уровень начала строки, чем ее конца, в силу субъективных привычек чтения и отладки;
      • 3 символа "Obj" можно заменить 1 по вашему усмотрению;
      • пожертвовав не более двух строк по вертикали, можно избавиться и от необходимости дописывать ".Obj".

      Кроме замены указанных конструкций кода, auto_ptr применим и для хранения агрегированных объектов внутри объектов-контейнеров дабы отказаться от ручного освобождения в деструкторе, что в свою очередь в некоторых случаях отказаться и от самого деструктора.

      З.Ы. Не претендую пока на абсолютную правильность и корректность такого способа, отсутствие подводных камней и прочего, а лишь выношу на обсуждение. Для отыскания истины)
          Я на работе набросал логичноподобный код. но я не насыщал интерфейс логикой. мне показалось это лишним. он служит только для уничтожения класса.
          и всю внутреннюю кухню всунул в record (объявления типа и интерфейса)
          пс. хотя насчет этого в 2009 глюк, но у меня не стояла задача делать совместимость.

          ну и я сделал авто создание. гдето так:
          ExpandedWrap disabled
            type
              TRecord<T:class, constructor> = record
              private
                inf: IInterface;
                function GetValue: T;
              public
                property Value: T read GetValue write SetValue;
              end;
             
            { TRecord<T> }
             
            function TRecord<T>.GetValue: T;
            begin
              if not Assigned(inf) then
                 inf := TContainer.Create(T.Create);
              Result := inf.GetObj;
            end;

          и тогда можно будет написать
          ExpandedWrap disabled
            var
              Strings: auto_ptr<TStringList>;
            begin
              Strings.Obj.LoadFromFile('.\TestFile.txt'); // объект создавать не надо он сам будет создан
              if (Strings.Obj.Count > 0) then
          Но накладываются ограничения что тип должен иметь конструктор по умолчанию без параметров. ибо будут глюки
          Сообщение отредактировано: ViktorXP -
          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
          0 пользователей:


          Рейтинг@Mail.ru
          [ Script execution time: 0,0467 ]   [ 17 queries used ]   [ Generated: 28.03.24, 08:23 GMT ]