Zagadkowe destruktory oraz std::list

0

www.ideone.com/mM5D2a
tutaj clear() wywoluje destruktory

www.ideone.com/y87XjV
tutaj clear() NIE wywoluje destruktorow

jak to mozliwe ze raz clear wywoluje destruktory a innym razem nie? RTTI? Ale skad wiadomo ze cos jest wskaznikiem czy nie?

  1. wywolanie jawne destruktora ktorego obiekt pokazuje na null (WTF?)
    www.ideone.com/tB0C6i
    czemu destruktor sie wykonal? I do tego (chyba) poprawnie

  2. Co za voodoo magic robi destruktor? Wiem ze niszczy obiekt, ale jak, co, dlaczego?

2

std::list nie wywołuje destruktorów, bo.. wskaźniki ich nie mają ;). A nawet jakby miały to skąd std::list miało by wiedzieć czy chcesz je wywołać i zniszczyć to, co jest pod wskaźnikami. Czasem faktycznie pożądane jest, by te wskaźniki były "własnością" listy - i wtedy możesz skorzystać ze wskaźników inteligentnych. Wtedy std::list wywoła delete (dla domyślnego alokatora) na inteligentnym wskaźniku (który najczęściej jest zwykłą strukturą), a ten wywoła delete na samym wskaźniku.

Ad.3. Destruktor w tym wypadku to normalna metoda i wywołujesz ją w ten sposób. Każda metoda to zwykła funkcja, która niejawnie przyjmuje argument - wskaźnik na obiekt, na którym ma zostać wywołany. Jeżeli w metodzie nie korzystasz z niego - dereferencji żadnej nie będzie i nic się nie zepsuje.

Ad.4. Destruktory nie niszczą obiektów. Wywołują się po prostu, gdy obiekt ma zostać niedługo zwolniony. Z reguły zwalnia się tam pamięć, która została zaalokowana przez ciebie ręcznie albo obiekty / zasoby, które nie zostaną zwolnione automatycznie - np. uchwyty do plików i tak dalej.

2

RTTI między innymi deklaruje wirtualny destruktor.

0

@Rev

a skąd std::list wie kiedy wywołać destruktor lub nie. Wiem, że typy wbudowane nie mają destruktorów, ale jak to std::list rozpoznaje. Bo chyba musi być jakoś jawnie wywołane typu
~this(); //ok to this jest głupie, ale chyba przekazałem o co mi chodzi ;)
lub cokolwiek innego które wywołuje destruktor

  1. dziś czytałem dość sporo o tym i na wielu forach/stronach piszą ze destruktor niszczy obiekt (ale nie zwalnia pamięci) i wywołanie dwukrotnie destruktora to jest wielkie zło. Jeżeli tak nie jest to mogę (jeżeli destruktor nic nie robi) wywołać destruktor jawnie i 100 000 razy dla jakiegoś obiektu dynamicznie stworzonego i nic się nie stanie?

Jeżeli potrzeba to znajdę te strony, ale pewnie wkleję później bo było ich całkiem sporo

1

Samo std::list się tym nie zajmuje. Przyjmuje natomiast coś takiego jak allocator, czyli struktura opisująca zasady alokacji i dealokacji pamięci. Domyślnie jest to zwykłe new oraz delete. Więc alokując pamięć dla wskaźnika dostaniemy **wsk. delete wywołane na wsk nigdy nie wywoła przecież destruktora dla **wsk ;).

Ad. 4. Zależy w jaki sposób jest ten destruktor napisany. Może sprawdzać czy pamięć zarządzana przez nas została już zwolniona. Ale (np. ze względów wydajnościowych) nie musi tego zrobić i wtedy podwójne wywołanie destruktora może skończyć się źle.
Generalnie zasada jest taka: (o ile nie korzystamy z placement new) NIE wywołujemy destruktorów. Niech zrobi to runtime, gdy zrobimy delete albo wyjdziemy z obiektem poza scope.

0

muszę sobie to jakoś w kodzie pogrzebać. Bo każde słowo z Twojego postu rozumiem, ale jakoś zdania dla mnie są obce ;). Ale (chyba) już wiem jak pisać i czego szukać

ad 4) zasadę doskonale znam. Ale dziś miałem dość dziwny kod i chciałem wiedzieć jak działa dokładnie destruktor. Czy jeżeli nic nie robi (jest pusty) to czy nie popsuje czegoś jak wykona się dwukrotnie. Na to wychodzi że nie więc bardzo dobrze :)

a jeszcze pytanie, po co clear i erase wywołuje destruktor (z tego co zrozumiałem to nawet delete)? Skoro może wywołać tylko dla obiektów (a dokładniej ich kopii) a przecież takie obiekty nie wychodzą (chyba) poza dany scope więc i tak zakres wywoła odpowiednie rzeczy.

Edit. Przez co delete będzie wykonany dwukrotnie. A jeszcze tym bardziej źle gdy nie ustawimy tych obiektów na nulle. Rozumiem tylko taką przyczynę, że ktoś pisze DUUUUUZA metodę (więc już źle) i potrzebuję wcześniej zasobów

1

po co clear i erase wywołuje destruktor (z tego co zrozumiałem to nawet delete)?

One NIE wywołują destruktora. Robią delete i to delete (runtime) decyduje czy wykonać destruktor.

0

Ok już rozumiem, ale jeszcze ostatnie pytanie. Jak to jest, że to się kompiluję (że tak powiem)
Skoro przekazujemy obiekt (kopię) to jak może działać delete?

 
#include <iostream>

using namespace std;

class Foo{
public:
  Foo() {}
};

int main()
{
    Foo a;
    delete a;
    return 0;
}

ten kod nie działa, ale lista dla niego wywoła delete (wraz z destruktorem)

 
#include <iostream>

using namespace std;

class Foo{
public:
  Foo() {}
};

int main()
{
    Foo *a = new Foo();
    delete a;
    return 0;
}

tutaj lista wywoła delete, nie wywoła destruktora ale kod działa.

Wiem, że zapewne głupio piszę, ale troszkę dla mnie nie jest to do ogarnięcia jak działa ten delete z std::list

1

Ten pierwszy kod jest po prostu błędny i w momencie wywołania delete następuje undefined behaviour.
std::list alokuje wszystkim przekazanym mu obiektom pamięć. Jeżeli wstawisz do niego wskaźnik to będzie miał zaalokowany przez siebie wskaźnik na wskaźnik, który mu podałeś. Gdy usuwa ten element to wywołuje delete na wskaźniku, który sam zaalokował i NIE powoduje to oczywiście zniszczenia obiektu, który mu podałeś pod oryginalnym wskaźnikiem.

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