Перейти к содержанию
Fire Monkey от А до Я
  • 0

Не срабатывает деструктор


Mazzay

Вопрос

Опубликовано (изменено)

Ничего не приходит на ум! Что я делаю не так?

Под Windows delete вызывает деструктор, под Android — нет.

Unit1.h

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
//---------------------------------------------------------------------------
class TBoxItem : public TPanel
{
private:
	TLabel* tInfo;
public:
	__fastcall TBoxItem(TComponent* Owner, String fText);
	__fastcall ~TBoxItem();
};

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
  TButton *ButtonNew;
  TButton *ButtonDelete;
  TLabel *LabelConstructor;
  TLabel *LabelDestructor;
  void __fastcall ButtonNewClick(TObject *Sender);
  void __fastcall ButtonDeleteClick(TObject *Sender);
private:	// User declarations
  TBoxItem *bi;
public:		// User declarations
  __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------

extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Unit1.cpp

#include <fmx.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  bi = NULL;
}
//---------------------------------------------------------------------------
__fastcall TBoxItem::TBoxItem(TComponent* Owner, String fText) : TPanel(Owner)
{
  Form1->LabelConstructor->Text = Form1->LabelConstructor->Text + " OK";
	Parent = (TFmxObject*)Owner;
	tInfo = new TLabel(this);
	tInfo->Parent = this;
  tInfo->TextSettings->HorzAlign = TTextAlign::Center;
  tInfo->Align = TAlignLayout::Center;
  tInfo->Text = fText;
  Height = 32;
  Align = TAlignLayout::Bottom;
}
//---------------------------------------------------------------------------
__fastcall TBoxItem::~TBoxItem()
{
  Form1->LabelDestructor->Text = Form1->LabelDestructor->Text + " OK";
  delete tInfo;
}

void __fastcall TForm1::ButtonNewClick(TObject *Sender)
{
  if(!bi)
  {
    bi = new TBoxItem(this, "BoxItem");
    ButtonNew->Enabled = false;
    ButtonDelete->Enabled = true;
  }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ButtonDeleteClick(TObject *Sender)
{
  if(bi)
  {
    delete bi; // под Android деструктор не вызывается, объект не уничтожается ((
    bi = NULL;
    ButtonNew->Enabled = true;
    ButtonDelete->Enabled = false;
  }
}
//---------------------------------------------------------------------------

Windows (жму кнопку «new» — получаю «Constructor OK» и панель внизу экрана, жму «delete» — получаю «Destructor OK», панель удаляется)

2019-01-20_15-00-50.png.7b36a33f22b12d869f4da32dd9b80212.png

Android (жму кнопку «new» — получаю «Constructor OK» и панель внизу экрана, жму «delete» — «Destructor OK» не получаю, панель НЕ удаляется)

Screenshot_2019-01-20-14-57-02.jpeg.df516efd2c26ccd07cb235eb0af44e47.jpeg

C++Builder 10.2.3 Tokyo

delete bi; не вызывает деструктор. ((

Изменено пользователем Mazzay

Рекомендуемые сообщения

  • 0
Опубликовано
bi->Parent = NULL;

Если это вставить перед delete, как здесь описано, не помогает. Помогает, только если ещё и в конструкторе не указывать владельца «TPanel(NULL)», что не считаю нормальным:

__fastcall TBoxItem::TBoxItem(TComponent* Owner, String fText) : TPanel(NULL)

 

  • 0
Опубликовано (изменено)
bi->Parent = NULL;

Если это вставить перед delete, как здесь описано, не помогает. Помогает, только если ещё и в конструкторе не указывать владельца «TPanel(NULL)», что не считаю нормальным:

__fastcall TBoxItem::TBoxItem(TComponent* Owner, String fText) : TPanel(NULL)

//////////////////

В результате остановился на таком варианте, но он мне тоже не нравится:

bi->Parent = NULL;
#if defined(__ANDROID__) || defined(__APPLE__)
bi->DisposeOf();
#endif
delete bi;
bi = NULL;

 

Изменено пользователем Mazzay
  • 0
Опубликовано

может, доки прочесть?

в мобильных платформах используется ARC 

поэтому, пока есть хоть одна ссылка на объект, он не уничтожается

зато, когда ссылок нет, он уничтожается самостоятельно

вызов Delete для компонента нужен для сохранения кросс-платформенной совместимости

в Windows он работает, в ARC - пустой

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

  • 0
Опубликовано
2 часа назад, krapotkin сказал:

может, доки прочесть?

в мобильных платформах используется ARC 

поэтому, пока есть хоть одна ссылка на объект, он не уничтожается

зато, когда ссылок нет, он уничтожается самостоятельно

вызов Delete для компонента нужен для сохранения кросс-платформенной совместимости

в Windows он работает, в ARC - пустой

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

Выходит, без условной компиляции не обойтись?

В деструкторах у меня уничтожаются все дочерние объекты, что в свою очередь должно убирать их с экрана, например. Писать вместо деструкторов функции типа «Hide», а память пусть остаётся занятой?

  • 0
Опубликовано

.RefCount дает количество ссылок на объект, если <>0 значит вы еще не все ссылки удалили

Если компонент создан aa := TMyComp.Create(OwnerComponent) то как минимум нужно еще и удалить его у владельца. про удаление компонентов тут 8 страниц недавно написали

Если вы создаете его динамически, то не указывайте владельца, тогда Component->Parent = NULL; FreeAndNil(Component); будет достаточно

 

  • 0
Опубликовано

Parent = NULL не могу. Мой объект — это компонент, который размещается на этом Parent. Можно сделать Owner = NULL, но это как-то, ИМХО, неправильно.

  • 0
Опубликовано

вот проверил специально. C++ нет у меня но думаю, не отличается ничем

  b2 := TButton.Create(nil);
  b2.Parent := Self;
  b2.SetBounds(50,50,150,30);

потом

  m1.Lines.Add(inttostr(b2.RefCount));
  b2.Parent:=NIL;
  m1.Lines.Add(inttostr(b2.RefCount));
  FreeAndNil(b2); // <-- тут попадает в деструктор

для проверки

 TButton=class(FMX.StdCtrls.TButton)
  public
    destructor Destroy; override;
  end;
destructor TButton.Destroy;
begin
  ;
  inherited; // <--- breakpoint here
end;

если создавать TButton.Create(Self) то нужно больше движений. Просто не нужно так делать ))))

  • 0
Опубликовано
1 час назад, krapotkin сказал:

если создавать TButton.Create(Self) то нужно больше движений. Просто не нужно так делать ))))

Я и писал:

В 20.01.2019 в 19:31, Mazzay сказал:

Помогает, только если ещё и в конструкторе не указывать владельца «TPanel(NULL)», что не считаю нормальным:


__fastcall TBoxItem::TBoxItem(TComponent* Owner, String fText) : TPanel(NULL)

 

 

 

21 час назад, Mazzay сказал:

Можно сделать Owner = NULL, но это как-то, ИМХО, неправильно.

Почему не нужно передавать указатель на себя потомку?

  • 0
Опубликовано
В 24.01.2019 в 13:08, krapotkin сказал:

если создавать TButton.Create(Self) то нужно больше движений.

Кстати, в TComponent Owner объявлен как «unsafe». Почему тогда Create(Self) увеличивает счётчик ссылок дополнительно ещё на единицу?

class PASCALIMPLEMENTATION TComponent : public TPersistent
{
...
private:
	__unsafe TComponent* FOwner;
...  
public:
	__property TComponent* Owner = {read=FOwner};
...
};

 

  • 0
Опубликовано (изменено)

Или вот, в случае с Delphi:

type
  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)
  private
    [weak] FOwner: TComponent;

[weak] FOwner

Изменено пользователем Mazzay
  • 0
Опубликовано (изменено)
4 часа назад, Mazzay сказал:

Кстати, в TComponent Owner объявлен как «unsafe». Почему тогда Create(Self) увеличивает счётчик ссылок дополнительно ещё на единицу?

Owner объявлен как __unsafe для того, чтобы объекты не увеличивали счетчик ссылок у их владельцев. То есть, это для того, чтобы когда мы пишем, например: TButton *btn = new TButton(Form1), то счетчик ссылок у Form1 не изменился.

Когда мы указываем владельца при создании объекта, то он (создаваемый объект), попадает в список того, чем владеет владелец, поэтому счетчик ссылок создаваемого объекта увеличивается.

Изменено пользователем d7d1cd
  • 0
Опубликовано
25 минут назад, krapotkin сказал:

Причем сразу на 2 )) каюсь, я не стал выяснять почему

Во-во. А мне надо освободить память из-под объекта. Какие ещё ссылки на него, которые запомнил Владелец, обнулить?

  • 0
Опубликовано (изменено)

Счётчик увеличивается на 2 потому что одну ссылку хранит владелец, а вторую указатель bi.

Тут я не прав. Есть статья Бровина Ярослава. Там сказано, что каждый компонент с фокусом получает дополнительную ссылку. Я проверил, так происходит только тогда, когда при создании объекта указывается его владелец. Поэтому не указывай владельца при создании объекта.

Владелец нужен только для автоматического удаления того, кем он владеет при удалении его самого. У тебя же не тот случай.

Изменено пользователем d7d1cd
  • 0
Опубликовано (изменено)

Вот код добавления кнопки и ее удаление без условной компиляции, который работает и на Windows и на Android, а так же, когда при создании указывается владелец:

// btn объявлен в описании класса TForm1

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
 btn = 0;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 btn = new TButton(this);
 btn->Text = L"Created!";
 btn->Parent = this;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 if(!btn) return;
 btn->Parent = 0;
 RemoveComponent(btn);
 delete btn;
 btn = 0;
}

 

Изменено пользователем d7d1cd

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...