2014-06-09 10 views
8

Jak pokazano here, można użyć dynamic_cast wykryć usuniętą wskaźnik:Jak usunięcie wskaźnika wykryć stosując dynamiczną obsady

#include <iostream> 

using namespace std; 

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

class B : public A 
{ 
public: 
    B() {} 
}; 

int main() 
{ 
    B* pB = new B; 

    cout << "dynamic_cast<B*>(pB) "; 
    cout << (dynamic_cast<B*>(pB) ? "worked" : "failed") << endl; 

    cout << "dynamic_cast<B*>((A*)pB) "; 
    cout << (dynamic_cast<B*>((A*)pB) ? "worked" : "failed") << endl; 

    delete pB; 

    cout << "dynamic_cast<B*>(pB) "; 
    cout << (dynamic_cast<B*>(pB) ? "worked" : "failed") << endl; 

    cout << "dynamic_cast<B*>((A*)pB) "; 
    cout << (dynamic_cast<B*>((A*)pB) ? "worked" : "failed") << endl; 

} 

wyjście:

dynamic_cast<B*>(pB) worked 
dynamic_cast<B*>((A*)pB) worked 
dynamic_cast<B*>(pB) worked 
dynamic_cast<B*>((A*)pB) failed 

Wyjaśnia, że Wykryto usunięcie tabeli vtable.

Ale zastanawiam się, jak to możliwe, ponieważ nie nadpisujemy uwolnionej pamięci?

Czy to rozwiązanie jest w pełni przenośne?

Dzięki

+0

Zgaduję, że 'dynamic_cast ' używa [RTTI] (http://en.wikipedia.org/wiki/Run-time_type_information) do sprawdzenia poprawności typu, który jest rzutowany na. –

+0

Podejrzewam, że jest to zachowanie zależne od platformy. –

+0

Program Visual Studio 2013 zgłasza wyjątek '__non_rtti_object' z tym kodem. –

Odpowiedz

6

pierwsze, próbuje użyć usuniętego obiektu w żadnej formie wyników w niezdefiniowanej zachowań: cokolwiek wynikać widać może się zdarzyć!

Powodem obserwowanego zachowania jest po prostu to, że obiekt zmienia typ podczas destrukcji: od bycia obiektem konkretnego typu zmienia się we wszystkich typach w hierarchii. W każdym punkcie funkcje wirtualne zmieniają się, a vtable (lub podobne) zostaje zastąpione. dynamic_cast<...>() po prostu wykrywa tę zmianę w bajcie strored w lokalizacji obiektu.

Jeśli masz ochotę pokazać, że ta technika nie działa niezawodnie, możesz po prostu ustawić zawartość usuniętej pamięci na losowy wzorzec bitowy lub wzór bitowy obiektu najbardziej pochodnego typu: losowy bit Wzór prawdopodobnie powoduje awarię, a memcpy() prawdopodobnie twierdzi, że obiekt to nadal życie. Oczywiście, ponieważ jest to niezdefiniowane zachowanie, wszystko może się zdarzyć.

Jeden odpowiedniej sekcji na to 3,8 [basic.life] ustęp 5:

Przed żywotność obiektu rozpoczęła ale po przechowywaniu którym obiekt zajmie została przydzielona lub po życia obiekt został zakończony i przed przechowywaniem, który zajmował obiekt, jest ponownie wykorzystywany lub zwalniany, można użyć dowolnego wskaźnika, który odnosi się do miejsca przechowywania, w którym znajduje się lub znajduje się obiekt, ale tylko w ograniczony sposób. W przypadku przedmiotu w budowie lub zniszczenia patrz 12.7. W przeciwnym razie taki wskaźnik odnosi się do przydzielonej pamięci (3.7.4.2), a użycie wskaźnika, jak gdyby wskaźnik był typu void*, jest dobrze zdefiniowany. Dozwolone jest wskazywanie przez taki wskaźnik, ale wynikowa wartość l może być używana tylko w ograniczony sposób, jak opisano poniżej. Program niezdefiniowane zachowanie, jeżeli:

  • ...
  • wskaźnik jest używany jako argumentu o dynamic_cast (5.2.7). ...

dziwne, na przykład ostatniego naboju na dynamic_cast nie używa dynamic_cast.

Oczywiście obiekt prawdopodobnie również został zwolniony, w takim przypadku powyższe gwarancje nawet nie mają zastosowania.

Powiązane problemy