Create a usuwanie obiektu

0

Witam.

Mam naleciałości z C++ dlatego mój post.
Jak jest ze zwalnianiem pamięci po utworzeniu obiektu poprzez konstruktor create?
Np. Tworzę klasę ze zmienną statyczną Integer i dynamiczną array of Integer w public.
W konstruktorze oczywiście inicjalizacja dynamicznej..... SetLengtch().
Mam też destruktor Destroy:

....i teraz

  1. Czy w destruktorze muszę usuwać za pamięci zmienną dynamiczną czy wystarczy go po prostu
    wywołać i zajęta pamięć prez obiekt jest czyszczona automatycznie

  2. Czy cały obiekt utworzony przez konstruktor jest dynamicznie alokowany w pamięci czy tylko te zmienne które są tworzone w konstruktorze dynamiczne.

Obiekty oczywiście tworzę poprzez obiekt.create nie przez definicję wskaźnika i potem przez niego obiekt jak w c++.

0

w delphi nic nie dzieje się "automagicznie". Jak masz w klasie zmienne inne niż typu prostego (integer, char, string, double, ...) lub tablice (dynamiczne i statyczne) to sam musisz je utworzyć oraz w 99,99% przypadków zwolnić. Ten 0,01% to np. wątki, które mają ustawione FreeOnTerminate na True czy też elementy listy, która ma ustawione OwnsObjects na True. Osobną kwestią są komponenty, które może zwalniać ich właściciel (przekazywany w konstruktorze) w momencie własnej destrukcji. Jest taka zasad mówiąca "co sam stworzyłeś, sam zwolnij". Trzymanie się jej pozwoli Ci zaoszczędzić sobie wiele pracy przy szukaniu przyczyny, że "program cały czas puchnie w pamięci", pozwoli wyeliminować (albo bardziej poprawnie nie powstać) większość wycieków pamięci, jakie zdarzają się początkującym.

Jedynymi elementami, które "zwalniają się same" są interfejsy, które mają licznik odwołań i w momencie, kiedy spadnie on do 0 pamięć po nich jest zwalniana a obiekt niszczony.

Co do drugiego pytania to konstruktor nic sam z siebie nie tworzy. Jeśli klasa ma pole, które jest obiektem to właśnie konstruktor jest dobrym miejscem na utworzenie instancji danej klasy a destruktor na jego zniszczenie

1
abrakadaber napisał(a):

w delphi nic nie dzieje się "automagicznie".
Jak masz w klasie zmienne inne niż typu prostego (integer, char, string, double, ...) lub tablice (dynamiczne i statyczne) to sam musisz je utworzyć oraz w 99,99% przypadków zwolnić. Ten 0,01% to np. wątki, które mają ustawione FreeOnTerminate na True czy też elementy listy, która ma ustawione OwnsObjects na True. Osobną kwestią są komponenty, które może zwalniać ich właściciel (przekazywany w konstruktorze) w momencie własnej destrukcji. Jest taka zasad mówiąca "co sam stworzyłeś, sam zwolnij". Trzymanie się jej pozwoli Ci zaoszczędzić sobie wiele pracy przy szukaniu przyczyny, że "program cały czas puchnie w pamięci", pozwoli wyeliminować (albo bardziej poprawnie nie powstać) większość wycieków pamięci, jakie zdarzają się początkującym.

Jedynymi elementami, które "zwalniają się same" są interfejsy, które mają licznik odwołań i w momencie, kiedy spadnie on do 0 pamięć po nich jest zwalniana a obiekt niszczony.

A to nie do końca prawda, dzieje się samo w przypadku najnowszej wersji czyli Delphi XE4:
http://blog.marcocantu.com/blog/automatic_reference_counting_for_delphi.html
Są Jeszce kombinacje z tzw. Smart Pointers, ale to inna bajka, za to efekt ten sam. "Magia" w przypadku automatycznego zwalaniania referencji.
http://blog.barrkel.com/2008/09/smart-pointers-in-delphi.html

abrakadaber napisał(a):

Co do drugiego pytania to konstruktor nic sam z siebie nie tworzy. Jeśli klasa ma pole, które jest obiektem to właśnie konstruktor jest dobrym miejscem na utworzenie instancji danej klasy a destruktor na jego zniszczenie

Osobiście zamiast przeładować constructori destructor, zalecam napisać metodę AfterConstrucion i BeforeDestruction (są zadeklarowane jako wirtualne publiczne na poziomie TObject).
Co do właściwości, które muszę być zainicjowane to stosuję tzw. lazy create:

type
  TMyClass = class
  strict private
    FSourceConn: TADCustomConnection;    
    function GetDestConn: TADCustomConnection;
  public
    property SourceConn: TADCustomConnection read GetSourceConn;
  end;  

implementation

function TmYcLASS.GetDestConn: TADCustomConnection;
begin
  if not Assigned(FSourceConn) then
    FSourceConn := TADCustomConnection.Create(nil);
  Result := FSourceConn;
end;

Różnica pomiędzy utworzeniem obiektu FConnection w konstruktorze a powyższą metodą jest taka, że to wyżej utworzy ten obiekt dopiero wtedy kiedy będzie potrzebny i nie wcześniej.

0

w delphi nic nie dzieje się "automagicznie"

Nie do końca prawda. Tablice dynamiczne (array of integer, bez podania indeksów) są zwalniane automagicznie.
Podobnie stringi.

Dodatkowo interfejsy (takie jak COM, ale niekoniecznie muszą COM używać) mają automatyczny reference counting.

0

w delphi nic nie dzieje się "automagicznie". Jak masz w klasie zmienne inne niż typu prostego (integer, char, string, double, ...) lub tablice (dynamiczne i statyczne) to sam musisz je utworzyć oraz w 99,99% przypadków zwolnić.

Głupoty alert!

Jedynymi elementami, które "zwalniają się same" są interfejsy, które mają licznik odwołań i w momencie, kiedy spadnie on do 0 pamięć po nich jest zwalniana a obiekt niszczony.

Głupoty alert! O ile interfejsy się same zwalniają, to nie są jedynymi takimi elementami.

Nie do końca prawda. Tablice dynamiczne (array of integer, bez podania indeksów) są zwalniane automagicznie.
Podobnie stringi.

Dodatkowo interfejsy (takie jak COM, ale niekoniecznie muszą COM używać) mają automatyczny reference counting.

Tak, to jest poprawne. W rzeczywistości, stringi to specjalny przypadek tablic dynamicznych. (mówimy o ansistring).

  1. Czy w destruktorze muszę usuwać za pamięci zmienną dynamiczną czy wystarczy go po prostu
    wywołać i zajęta pamięć prez obiekt jest czyszczona automatycznie

Wywołanie destruktora jest wystarczające.

  1. Czy cały obiekt utworzony przez konstruktor jest dynamicznie alokowany w pamięci czy tylko te zmienne które są tworzone w konstruktorze dynamiczne.

Wszystko jest alokowane w pamięci. Co więcej konstruktor niejawnie inicjalizuje wszystkie zmienne.
Natomiast nie jestem przekonany czy dobrze rozumiem pytanie, możesz zadać je jeszcze raz jeżeli nie jesteś pewien.

0

... chodziło mi czy poprzez zwykle wywołanie konstruktora notacja obiekt.Create jest alokowanie dynamiczne w pamięci czy tzw statyczne a stosie (wiem wiem stos to też pamięć ale z inną szybkością obsługi) bo w c++ jest tak że obiekty statyczne są na stosie a dynamiczne poprzez operator new. Do statycznych odnosimy się przez '.' a dynamicznych poprzez'->'

1
adam____ napisał(a):

... chodziło mi czy poprzez zwykle wywołanie konstruktora notacja obiekt.Create

Nie ma takiego odwołania, jest TypObiektu.Create...

adam____ napisał(a):

... jest alokowanie dynamiczne w pamięci czy tzw statyczne a stosie

Dynamicznie.

adam____ napisał(a):

... bo w c++ jest tak że obiekty statyczne są na stosie a dynamiczne poprzez operator new. Do statycznych odnosimy się przez '.' a dynamicznych poprzez'->'

Kto ci taką wodę z mózgu zrobił?

class Foo { public: int x; };
Foo f,*w=&f;
w->x=0; // 'w' jest na stosie
Foo &r=*(new Foo);
r.x=0; // 'r' jest na stercie 
delete &r;
0

Głupoty alert! O ile interfejsy się same zwalniają, to nie są jedynymi takimi elementami.
Interfejsy się zwalniają, o ile ich klasa dziedziczy po TInterfacedObject.
Jedyne co mamy w interfejsach zapewnione, to automatyczne wywoływanie metod _AddRef i _Release. Intencją jest, by służyło to zliczaniu referencji, ale mamy wolność w implementacji WTFów, np. niszczenia obiektu już przy pierwszym Release, albo nigdy.

... bo w c++ jest tak że obiekty statyczne są na stosie a dynamiczne poprzez operator new. Do statycznych odnosimy się przez '.' a dynamicznych poprzez'->'
w Delphi obiekty klas (class) są zawsze tworzone na stercie. Jak sprawdzisz sizeof(jakiśObiekt) to dostaniesz 4 albo 8 - rozmiar wskaźnika.

0

idiota alert! Może jakiś przykład albo sprostowanie tego co napisałem jak już...

Jak prostować coś co jest zupełnie odwrotne niż prawda?
Serio, co jak co ale gdy mi się zdarzy jakakolwiek pomyłka, to jestem minusowany na maksa, natomiast ty możesz walić głupoty jak chcesz? Co to, to nie.
Już nawet widzę że zminusowałeś mój post, mimo że to ja mam rację a nie ty. Cóż za problematyczność.

... chodziło mi czy poprzez zwykle wywołanie konstruktora notacja obiekt.Create

taka notacja to nie jest zwykłe wywołanie konstruktora.

jest alokowanie dynamiczne w pamięci czy tzw statyczne a stosie (wiem wiem stos to też pamięć ale z inną szybkością obsługi)

Wytłumacz mi czym prędkość RAM różni się od prędkości RAM? Czyżby komputery miały jakiś nowy typ pamięci jakiego nie znam... Stos ma dokładnie taką samą prędkość.

bo w c++ jest tak że obiekty statyczne są na stosie a dynamiczne poprzez operator new.

W pascalu object to odpowiednik twojego na stosie (chociaż wątpię czy to w rzeczywistości na stosie jest), a class to odpowiednik wywołania new.

0

Wytłumacz mi czym prędkość RAM różni się od prędkości RAM?
Obsługa sterty jest zwykle wolniejsza niż stosu: sterta ma skomplikowane algorytmy alokacji, a stos tylko wskaźnik wierzchołka, który jest zmniejszany bądź zwiększany.
Sterta często wymaga dodatkowej dereferencji wskaźnika, czyli więcej instrukcji procesora idzie na to, by dostać się do pola obiektu albo by wykonać skok do metody wirtualnej.
RAM nie różni się od RAM-u, zarówno sterta jak i stos to tylko umowne obszary tej samej pamięci, ale to nie wyklucza różnicy w wydajności tych abstrakcyjnych tworów.

0

Obsługa sterty jest zwykle wolniejsza niż stosu: sterta ma skomplikowane algorytmy alokacji, a stos tylko wskaźnik wierzchołka, który jest zmniejszany bądź zwiększany.

a) Stos ma M$ Windows takie same "prawa" jak sterta.
b) Alokacja nie jest prędkością. Większość systemów przydziela zazwyczaj pamięć na zapas wobec czego większość requestów jest wykonywana dosyć szybko (dochodzą do tego skomplikowane algorytmy np. unikania żądania tego samego bloku)
Prędkość uznałem za prędkość odczytu/zapisu, co nie jest prawdą.

Sterta często wymaga dodatkowej dereferencji wskaźnika, czyli więcej instrukcji procesora idzie na to, by dostać się do pola obiektu albo by wykonać skok do metody wirtualnej.

Pole obiektu zazwyczaj kosztuje tyle co każda inna zmienna lokalna (nie biorąc pod uwagę cachowania). Po prostu na początku przy wejściu do metody pobierany jest adres bazowy klasy. Metoda wirtualna to akurat zupełnie inna sprawa, nie za bardzo rozumiem co ona tutaj ma do reszty.

RAM nie różni się od RAM-u, zarówno sterta jak i stos to tylko umowne obszary tej samej pamięci, ale to nie wyklucza różnicy w wydajności tych abstrakcyjnych tworów.

Otóż dla sterowników/sprzętu nie ma żadnej różnicy czy to stos czy sterta czy WTF. Alokacja zajmuje coś, zgoda, ale nie zgodzę się że prędkości są różne. To tak jakbym powiedział, że silnik w samochodzie X i Y odpala się w różnym czasie, ale mają taką samą prędkość i przyśpieszenie. Czy to znaczy że któryś z nich jest szybszy? Nie. Już nie mówiąc o tym że są zaawansowane algorytmy które skracają i bardzo upraszczają alokację.

0 użytkowników online, w tym zalogowanych: 0, gości: 0