2014-10-29 2 views
2

Я запутался о некоторых деталях дикого указателя и оборванных указатель, вот мой код:Почему висячий указатель может перейти к объекту?

#include <iostream> 
using std::cout; 
using std::endl; 

class A 
{ 
public: 
    void Func() { cout << "Func of class A, the address is:" << this <<endl; } 
}; 

void Test(void) 
{ 
    A *p; 

    //get an error in VS2013 because of uninitialized pointer. 
    //But it's ok in g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2 
    p->Func();  // wild pointer, ((1)) 

    { 
     A a; 
     p = &a; 
     p->Func(); 
    } 

    p->Func(); //dangling pointer ((2)) 
} 

int main() 
{ 
    Test(); 
    return 0; 
} 

Результаты подобны следующим образом:
Окна:
Func of class A, the address is:003CFD47 Func of class A, the address is:003CFD47

Ubuntu:
Func of class A, the address is:0xb74ef39d Func of class A, the address is:0xbff85a3b Func of class A, the address is:0xbff85a3b

Мои вопросы:
(1) g ++-компилятор let the wil e pointer pass at ((1)), даже при запуске кода кажется, что это «некоторый объект». почему это может произойти? Это ошибка компилятора?

(2) Насколько я знаю, после блочных предложений p будет свисающим указателем на ((2)). Но почему можно перейти к Func()? Поскольку пространство, занимаемое объектом a, не перезаписывается другим приложением?

+3

Это неопределенное поведение. –

+0

который есть? висячий указатель? @ πάνταῥεῖ – kkwang

+1

@wjk Доступ к нему/его разыменование. –

ответ

4

p первоначально неинициализирован, поэтому он содержит любое случайное значение, которое произошло в области стека вызовов, которая резервируется для p. Это то, что вы видите в первом выпуске cout.

Затем вы создаете объект и назначаете его адрес p, который вы видите на втором выходе cout.

Затем объект выходит из сферы действия и освобождается, но вы ничего не переназначаете до p, поэтому он несет в себе существующее значение, которое вы видите в третьем cout выводах.

При вызове метода объекта с помощью недействительного указателя, хотя технически неопределенное поведение, как правило, ничего плохого не произойдет, если вы не разыщите указатель для доступа к любым членам класса, включая любые виртуальные методы, которым требуется указатель VMT ,

Способ вызов действительно просто вызов функции с дополнительным параметром скрытых this, так что ваш пример кода действительно делает следующее с точки зрения компилятора:

#include <iostream> 
using std::cout; 
using std::endl; 

class A 
{ 
public: 
    static void Func(A* this) { cout.operator<<("Func of class A, the address is:").operator<<((void*)this).operator<<(&endl); } 
}; 

void Test(void) 
{ 
    A *p; // initialized with random value 

    A::Func(p); 

    { 
     A a; // note: allocates only 
     A::A(&a); // then constructs 
     p = &a; 
     A::Func(p); 
     A::~A(&a); 
    } 

    A::Func(p); 
} 

int main() 
{ 
    Test(); 
    return 0; 
} 
Смежные вопросы