CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Usunięcie dynamicznie utworzonych komponentów
Strona 1 z 1

Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 01:56
przez swiezak
Witam,
Utworzyłem sobie kilka komponentów typu TLabel,

KOD cpp:     UKRYJ  
        Napisy = new TLabel*[LiczbaNapisow];
                for (int i=1; i<LiczbaNapisow; i++)
        {
                Napisy[i]=new TLabel(this);
                Napisy[i]->Parent=ScrollBox1;
                Napisy[i]->Width=50;
                Napisy[i]->Top=50+30*i;
                Napisy[i]->Left=500;
                Napisy[i]->Caption=FloatToStr(i);
        }



ale nie wiem za bardzo jak mam je usunąć by zniknęły z formatki zwalniając przy tym pamięć?

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 10:30
przez Cyfrowy Baron
Źle tworzysz te dynamiczne komponenty i masz tutaj gigantyczny wyciek pamięci. Chcesz tworzyć dynamicznie obiekty w oparciu o tablicę, to powinieneś okreslić rozmiar tej tablicy z góry, czyli ustalić maksymalną liczbę takich obiektów.

Plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:
        TLabel *Napisy[100]; /* maksymalnie 100 obiektów typu TLabel */


Plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
 for (int i = 1; i < LiczbaNapisow; i++)
 {
  if(i > 100) break;

  Napisy[i] = new TLabel(this);
  Napisy[i]->Name = "Napisy" + (String)i; /* nadaj nazwę */

  Napisy[i]->Parent = ScrollBox1;
  Napisy[i]->Width = 50;
  Napisy[i]->Top = 50+30*i;
  Napisy[i]->Left = 500;
  Napisy[i]->Caption = FloatToStr(i);
 }


Gdy masz komponenty i ich nazwy niszczysz je poprzez nazwę:

KOD cpp:     UKRYJ  
delete Napisy1;


Jeżeli chcesz tworzyć komponenty w nieokreślonej ilości, to posłuż się vector'ami i zapoznaj się z tym wątkiem: http://programowanie.cal.pl/forum/viewtopic.php?f=2&t=1136&p=7809&hilit#p7804

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 10:42
przez Corvis
Baronie, nie lepiej to ładować to TObjectList ?? i potem wywalać całą liste ?? Nie trzeba się martwić o zwalnianie każdego elementu gdyż usunięcie całej listy automatycznie zwolni każdy jej element.

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 11:12
przez polymorphism
Źle tworzysz te dynamiczne komponenty i masz tutaj gigantyczny wyciek pamięci. Chcesz tworzyć dynamicznie obiekty w oparciu o tablicę, to powinieneś okreslić rozmiar tej tablicy z góry, czyli ustalić maksymalną liczbę takich obiektów.

Nie wiem, gdzie Ty tu widzisz wyciek (pomijam sprawę czyszczenia i usuwania tej tablicy, wszak jest to przedmiot tego wątku). Jak na moje oko wszystko jest ok (no, może nie wszystko. Nie rozumiem, dlaczego indeksuje od jednego).

@swiezak: jeśli chodzi o zwalnianie, robisz to w odwrotnej kolejności do tworzenia:
KOD cpp:     UKRYJ  
for (int i = 1; i < LiczbaNapisow; i++)
{
        delete Napisy[ i ];
}

delete[] Napisy;


Potwierdzę to, co było napisane wcześniej. Zamiast bawić się gołymi tablicami dynamicznymi, użyj vectora lub klasy TObjectList. W przypadku klas pochodnych od TObject, a do tych niewątpliwie zaliczają się labele, druga opcja wydaje się sensowniejsza.

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 11:40
przez Cyfrowy Baron
polymorphism napisał(a):Nie wiem, gdzie Ty tu widzisz wyciek


U mnie ten kod:

KOD cpp:     UKRYJ  
 Napisy = new TLabel*[LiczbaNapisow];


wogóle się nie kompiluje, otrzymuję komunikat błędu:


[BCC32 Error] Unit1.cpp(44): E2034 Cannot convert 'TLabel * *' to 'TLabel *'



Nie wiem więc jak może wyglądać deklaracja obiektu Napisy, by ten kod się wogóle skompilował. Dlatego przyjąłem takie rozwiązanie dla testu:

Plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:        // User declarations
       TLabel *Napisy[];


Plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
 int LiczbaNapisow = 10;

 for (int i=1; i<LiczbaNapisow; i++)
 {
 Napisy[i]=new TLabel(this);
 Napisy[i]->Parent = Form1;//ScrollBox1;
 Napisy[i]->Width=50;
 Napisy[i]->Top = 50 + 30*i;
 Napisy[i]->Left=80;
 Napisy[i]->Caption=FloatToStr(i);
 }


To jednak wywołuje błąd. Program nie daje się zamknąć. Zakładam więc, że są jakieś problemy z adresami. Po określeniu rozmiaru tablicy problemy znikają.

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 11:44
przez polymorphism
Nie wiem więc jak może wyglądać deklaracja obiektu Napisy, by ten kod się wogóle skompilował

W treści błędu masz nawet podpowiedź:
KOD cpp:     UKRYJ  
TLabel** Napisy;

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 12:07
przez Cyfrowy Baron
polymorphism napisał(a):W treści błędu masz nawet podpowiedź:


Kombinowałem, ale nie wiedzieć dlaczego nieco inaczej:

  kod niepoprawny
  
KOD cpp:     UKRYJ  
TLabel** Napisy[];
  




Co się tyczy TObjectList to skoro powiedziało się A to należałoby powiedzieć i B.

Plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:        // User declarations
       TObjectList *LabelList;


Plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
/* konstruktor klasy formularza */
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 LabelList = new TObjectList();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 /* dodawanie nowych obiektów do listy, co jest tutaj równoznaczne z ich tworzeniem */
 static int nr = 0;

 int posY = 50;

 TLabel *Label = new TLabel(this);
 Label->Parent = this;
 Label->Left = 80;
 Label->Top = posY + (30 * nr);
 Label->Caption = "Label" + (String)nr;

 LabelList->Add(Label);

 nr++;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 /* odwoływanie się do konkretnego elementu listy z wykorzystaniem polimorfizmu */

 dynamic_cast<TLabel*>( LabelList->Items[2] )->Caption = "Zmiana etykiety"; /* Items[2] - trzeci element listy licząc o 0 */
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
 /* usuwanie konkretnego obiektu */
 LabelList->Remove( dynamic_cast<TLabel*>( LabelList->Items[2] ) ); /* trzeci obiekt */

 /* usuwanie obiektu poprzez usunięcie elementu listy */
 LabelList->Delete(5);  /* szósty element */
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 /* usuniecie wszystkich obiektów poprzez wyczyszczenie zawartości listy */
 LabelList->Clear();
}


Przy kasowaniu wybranego elementu z listy lub konkretnego obiektu (to samo) należy pamiętać, że elementy znajdujące się poniżej tego elementu przesuną się do góry listy, zajmując miejsce usuniętego elementu.

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 12:23
przez Corvis
Bardziej mi chodziło, o to czy ten sposób nie jest lepszy niż wektor lub ten co podałeś, niż o pisanie kodu :-). Ok następnym razem podam też kod

Re: Usunięcie dynamicznie utworzonych komponentów

Nowy postNapisane: wtorek, 15 marca 2011, 12:38
przez Cyfrowy Baron
Ja tylko zwróciłem uwagę, że jeżeli proponuje się jakieś rozwiązanie początkującemu użytkownikowi, to powinno się podać sposób użycia.

Corvis napisał(a):czy ten sposób nie jest lepszy niż wektor


Moim zdaniem jest po prostu inny. Być może obiekt TObjectList bazuje na czymś podobnym do vector'a. Posługiwanie się listą jest na pewno bardziej zrozumiałe dla kogoś, kto nie ma doświadczenia z vector'ami. Zauważ, że TObjectList oferuje wskaźnik na TObject, a jeżeli stworzysz vektor dla konkretnego typu to możesz odwoływać się bezpośrednio:
vector:
KOD cpp:     UKRYJ  
 LabelList.at(2)->Caption = "jakiś tekst";
 // lub:
 LabelList[2]->Caption = "jakiś tekst";


TObjectList:
KOD cpp:     UKRYJ  
 dynamic_cast<TLabel* >( LabelList->Items[2] )->Caption = "Zmiana etykiety";


W przypadku TObjectList nie można więc odwołać się bezpośrednio do elementu listy, gdyż każdy z tych elementów jest typu TObject, a nie typu przechowywanego obiektu.
Osobiście uważam, że TObjetList jest lepiej użyć tam, gdzie przechowuje się różnego rodzaju obiekty, gdyż w przypadku np. vector'a trzeba by utworzyć kilka list różnych typów.
Poza tym, jeżeli w TObjectList przechowujesz obiekty różnego typu, to przed odwołaniem się do wybranego obiektu w niektórych przypadkach musisz wiedzieć z jakim typem masz do czynienia.
Rodzi się jeszcze pytanie, czy typ TObjectList jest dostępny we wczesnych wersjach środowiska C++Builder.