Перейти к содержанию
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

вот проверил специально. 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 пользователей онлайн

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