2010-02-16 14 views
13

Znalazłem this one question asking the same thing, ale tylko "nowa" część została odebrana, więc znowu tutaj.Dlaczego operator usuwania musi być statyczny?

Dlaczego operator usuwania musi być statyczny? Jakoś to nie ma sensu. Nowy operator ma doskonały sens, tak jak konstruktor nie może być wirtualny, ani nowy operator. Jednak destruktor może (i powinien) być wirtualny, gdy używasz dziedziczenia, aby umożliwić niszczenie wykorzystywanych obiektów (za pomocą polimorfizmu) jako klasy bazowej.

Rozumiem, że gdy wywoływany jest operator delete, obiekt został już zniszczony, więc nie ma "tego". Jednak nadal ma sens, używając tego samego rozumowania, co w przypadku wirtualnego destruktora, aby operator delete pasował do nowego operatora, który utworzył obiekt.

To, co mam na myśli

class A 
{ 
    public: 
    virtual ~A() {} 
}; 

class B : public A 
{ 
    public: 
    void* operator new (size_t sz); 
    void operator delete (void* ptr, size_t sz); 
}; 

teraz jeśli robimy

A *ptr = new B(); 
delete ptr; // <-- fail 

Skasuj operatora (domyślnie) powinien był nazywany, ponieważ jest statyczna i nie jest znana (do niczego, ale tutaj drobny przypadek) w czasie kompilacji, którego operator delete jest poprawny.

Jednak wykonałem mały program testowy z powyższym kodem (po prostu malloc/free w operatorze new/delete i print statement w delete) i skompilowałem go za pomocą g ++. Uruchomienie tego całkiem nieoczekiwanie spowodowało wyjście w operatorze kasowania B.

Moje (prawdziwe) pytanie brzmi następująco: Czy jest jakiś niejawny "wirtualność" dla operatora usuwania? Czy jest to statyczne tylko w tym sensie? Czy jest to tylko funkcja g ++?

Zacząłem przeglądać specyfikację C++, ale muszę przyznać, byłem nieco przytłoczony, więc każda pomoc doceniona.

Odpowiedz

16

Odpowiedź w regułach językowych jest naprawdę w 12.5 [klasa.].

W przypadku usuwania za pomocą wskaźnika do klasy bazowej, destruktor musi być wirtualny lub występuje niezdefiniowane zachowanie. W przeciwnym razie implementacja musi określić typ dynamiczny usuwanego obiektu.

12,5/4 mówi, że gdy delete nie jest poprzedzony :: wówczas funkcja dealokacji jest określana przez patrząc delete w kontekście dynamicznego TYP Wirtualne destructor. Zapewnia to wirtualne wyszukiwanie, mimo że zawsze jest to funkcja składowa.

Raw przydział i dealokacji zdarzyć koncepcyjnie poza życia obiektu tak przez czas funkcja dealokacji to nazwać, nie ma już przedmiotem jest dostarczenie wirtualnego mechanizmu wyszukiwania ale zasady lookup zapewnić operator delete ma dynamiczną (virtual-lite!) mechanizm wyszukiwania. Oznacza to, że operacja usunięcia może sensownie być static bez utraty kontaktu z dynamicznym typem obiektu oryginalnego.

+0

Doskonale, dzięki! Grzebałem w 3.7.3 ... – falstro

+3

Jest także wiele istotnych rzeczy w 5.3.5, a także 3.7.3 i 12.5. Mimo że jest to praca referencyjna, wydaje się, że musisz przeczytać okładkę, aby przeczytać w przeciwnym razie, nigdy nie dowiesz się, czy istnieje mały akapit odnoszący się do czegoś, co znajduje się w zupełnie innej sekcji, niż w rzeczywistości. patrząc. –

1

delete operator jest dla dealokując tylko pamięć, a pamięć jest zwalniane dla najbardziej pochodzącego obiektu klasy jako całości - w jednej akcji - dokładnie tak samo jak z new operatora jest ona przeznaczona na całym najczęściej pochodzi klasy obiektu - obiekt klasy przekazany jako argument do konstrukcji new Class.

Dlatego gdy wykonujesz delete ptr; operator delete jest zawsze wywoływany tylko raz dla aktualnej najbardziej pochodnej klasy usuwanego obiektu, a dane o tym, która klasa jest, wyprowadzane z vtable jeśli wirtualny destruktor jest obecny lub typ wskaźnika, jeśli nie ma wirtualnego destruktora. Dlatego nie istnieje ukryta wirtualność dla operatora delete - cała wirtualność kończy się w punkcie wywołania destruktora.

+0

@roe: Najbardziej wyprowadzony operator klasy delete jest nazywany w ten sam sposób, w jaki wywoływany jest najbardziej wyprowadzony operator new. Jeśli więc masz różne banki, otrzymasz obiekty o różnych klasach przydzielonych z różnych banków, ale tylko jako całe obiekty, nigdy nie stanie się tak, że sub-obiekt pochodzi z jednego banku, a pochodna część klasowa obiektu pochodzi od innej. – sharptooth

+0

Tak więc operator, którego należy użyć, wywodzi się z tego, z jakiej klasy obiekt jest rzeczywisty (tzn. Szuka wirtualnego stołu, lub jak działa), brzmi, jakby operator miał jakąś domyślną wirtualność. Zakładając, że mam klasę C wywodzącą się z B, 'A * ptr = new C; delete ptr; 'nadal dzwoni do operatora usuwania B, co brzmi jak wirtualnie. Przepraszam za spamowanie komentarzy, staram się tylko nim owijać. – falstro

+0

@roe: operatory usuwania i nowe są dziedziczone. Ponieważ przeciąłeś je w klasie B, klasa C również ich użyje. Zobacz ładną tabelę tutaj: http://msdn.microsoft.com/en-us/library/c5at8eya.aspx – sharptooth

Powiązane problemy