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

Или как мне сделать, чтобы ссылок на объект не осталось, и он уничтожился? Этого недостаточно:

bi->Parent = NULL;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 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

он и не потомок вовсе. там архитектура через ... 

если ARC все равно все удалится когда удалится Parent

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 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 пользователей онлайн

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

×
×
  • Создать...