2010-12-17 5 views
6

Przekazuję kod do systemu Windows i jestem zakłopotany. Istnieje pewien kod, który uruchamia się automatycznie podczas uruchamiania, aby skopiować wskaźnik do wskaźnika, i uruchamia się ponownie przy wyjściu, aby usunąć wskaźnik do wskaźnika, jeśli nie jest on pusty.Pointer-to-Pointer ulega awarii w przypadku, gdy wskaźnik nie jest

ja stworzyliśmy przykładowy program do odtworzenia problemu

int main() 
{ 
    // Pointer to a Pointer, current crash. 
    InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 
    delete *ptrptr; // Crash here. 

    // Single pointer, works fine. 
    InterfaceClass* ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = object; 
    delete ptrptr; 

    // There are other cases where there are only 3 classes in the hierarchy. 
    // This also works fine. 
    InterfaceClass** ptrptr; 
    ConcreteOne* object = new ConcreteOne(); 
    ptrptr = (InterfaceClass**)(&object); 
    delete *ptrptr; 

    return 0; 
} 

Klasa Hierarchia wygląda następująco. Klasa podstawowa jest interfejsem z pewnymi czystymi funkcjami wirtualnymi i jest zawarta w wielu klasach całego programu w taki sposób, że wiele obiektów potencjalnie dziedziczy je z więcej niż jednego miejsca. Z tego powodu konkretna implementacja musi rozszerzyć ją o "publiczny wirtualny InterfaceClass". W tym przykładzie usunięcie "wirtualnego" rozwiązuje awarię.

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

class ConcreteClass : public virtual InterfaceClass { 
public: 
    ConcreteClass() { } 
    virtual ~ConcreteClass() {} 
}; 

class ConcreteOne : public ConcreteClass 
{ 
public: 
    ConcreteOne(void) {} 
    virtual ~ConcreteOne(void) {} 
}; 

class ConcreteTwo : public ConcreteOne 
{ 
public: 
    ConcreteTwo(void) {} 
    virtual ~ConcreteTwo(void) {} 
}; 

Odpowiedz

5

Czy wiesz, że typ wskaźnika nie ma nic wspólnego z typem, na który wskazuje? Innymi słowy, skąd masz wrażenie, że jeśli T1 dziedziczy z T2, to T1 * również dziedziczy z T2 *? To byłoby w błędzie. Teraz, jak to ma zastosowanie do twojej obecnej sytuacji?

InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 

Oto poważny problem z odlewaniem w stylu C. OK, więc oszczędza jakąś poziome miejsce, ale czy wiesz nawet jaki rodzaj obsady właśnie zrobiłeś? To nie jest to, o czym myślisz. W rzeczywistości wykonano reintpret_cast z typu ConcreteTwo * na niepowiązany typ InterfaceClass *! Teraz adres wskaźnika nie ma nic wspólnego z typem, którym mówisz, że jest.

Następnie rzuca się typem zinterpretowanej reinterpretacji do usunięcia, co natychmiast spowodowało naruszenie własnego zwieracza.

3

Cóż, kompilator ostrzega cię, postanowił zrobić to na swój sposób ...

nie można zrobić tego Obsada:

ptrptr = (InterfaceClass**)(&object); 

ponieważ object wskazuje na ConcreteTwo, który to nie to samo co InterfaceClass. InterfaceClass sub-obiekt ConcreteTwo znajduje się pod innym adresem. *ptrptr nie jest wskaźnikiem do instancji InterfaceClass.

Wskaźnik, który przekazuje się do delete, jest wskaźnikiem do ConcreteTwo, jednak użytkownik powiedział kompilatorowi, że jest to wskaźnik do InterfaceClass. delete zakłada, że ​​rzeczywiście jest to InterfaceClass, a zatem katastrofa.

1

Myślę, że problem jest w liniach rzutowania. BTW, jeśli usuniesz obsadę, którą wstawiłeś, kompilator dokładnie wyjaśni, na czym polega problem.

Jeśli naprawdę chcesz to zrobić, droga, która zdecydowanie odradzam, należy najpierw utworzyć tymczasowy:

ConcreteTwo* object = new ConcreteTwo(); 
InterfaceClass* ptr = object; 

następnie można wziąć swój adres i przypisać ją do zmiennej ptrptr:

InterfaceClass** ptrptr = &ptr; 

teraz można bezpiecznie usunąć go:

delete *ptrptr; 

Weź pod uwagę, że jeśli ptr wykracza poza zakres ptrptr, usuwanie prawdopodobnie ponownie się zawiesi.

Noah wyjaśnia, dlaczego Twój kod nie działa.

Powiązane problemy