2015-02-10 2 views
-2
[Global Scope] 

myClass *objA, *objB, *obj; 
int objnum; 

Я хочу, чтобы переключаться между objA и objB и назначать их в качестве альтернативы obj, поэтому в main() у меня есть:C++ 11 странное поведение с классами, указателей и глобальных деклараций области видимости

int main() 
{ 
    objA = new myClass(parameters...); 
    objB = new myClass(parameters...); 

    // start with objA; 
    objnum = 0; 
    obj = objA; 
} 

В некоторых точка называется функцией, которая переключается между двумя объектами:

void switchObjects() 
{ 
    if (++objnum > 1) objnum = 0; 
    obj = objnum == 0 ? objA : objB; 
} 

И в функции, в которой я использую объект, у меня есть:

void doYourJob() 
{ 
    int res = obj->work(); 
} 

Теперь странная вещь, что если я не назначайте obj к любому objA или objB, он все еще работает. Вместо этого я ожидал бы исключения. Даже если я делаю obj = NULL;, он все равно работает! Что это за вуду?

КИ, я мог бы предоставить другой пример, который приносит к тому же результату, без использования указателя NULL:

myClass *obj[2]; 
int objnum; 

void switchObject() 
{ 
    if (++objnum > 1) objnum = 0; 
} 

void doYourJob() 
{ 
    res = obj[objnum]->work(); 
} 

int main() 
{ 
    obj[0] = new myClass(parameters...); 
    obj[1] = new myClass(parameters...); 

    objnum = 0; 
} 

С кодом выше, независимо от значения objnum, я все еще получаю оба объекта работает вместе, даже если я звоню work() только на одном экземпляре.

И если я заменю функцию doYourJob() с этим:

void doYourJob() 
{ 
    int res1 = obj[0]->work(); 
    int res2 = obj[1]->work(); 
} 

Я всегда получаю результаты в два раза, как если бы я вызова функции work() дважды на каждом объекте.

+0

Вы не можете ожидать * ничего * от неопределенной программы. – molbdnilo

+4

Вызов функции-члена по нулевому указателю - это неопределенное поведение. Он часто работает, если функция-член фактически не использует членов класса. –

+0

Я отправил другой пример, который не имеет никакого отношения к указателям на нуль, кто-нибудь может дать мне ключ? –

ответ

4

Рассмотрим простой пример:

#include <iostream> 

struct X 
{ 
    void foo() { std::cout << "Works" << std::endl; } 
}; 

int main() { 
    X* x = nullptr; 
    x->foo(); 
} 

В большинстве компиляторов и на большинстве платформ, этот код будет отображаться работать нормально, несмотря на то, называется foo на нулевой указатель. Тем не менее, поведение технически undefined. То есть, язык C++ не дает никаких ограничений на то, что может произойти, если вы это сделаете.

Почему это работает? Ну, вызов функции-члена требует только знания типа объекта, на который он вызывается. Мы знаем, что x указывает на X, поэтому мы знаем, какую функцию вызывать: X::foo. Во многих случаях может быть сложно или даже невозможно узнать, указывает ли указатель на реальный объект, поэтому компилятор просто позволяет ему произойти. Тело функции в этом случае фактически не зависит от фактически существующего объекта X, поэтому он просто работает. Это не то, на что вы можете положиться.

+0

Я обновил сообщение с другим примером, который дает тот же результат. Не могли бы вы дать ему взглянуть? Нужно ли это делать с нулевыми указателями? –

+0

@MarkMiles [Невозможно воспроизвести] (http://ideone.com/kI36Bj). Вам нужно будет опубликовать новый вопрос с небольшим, компилируемым примером для кого-либо, кто поможет. –

+0

Ну, я не могу воспроизвести его ни на простом примере ...Моя фактическая программа намного больше, включает в себя много распределений памяти, таймеры, обратные вызовы, сокеты, аудио в реальном времени и т. Д. Проблема может быть где-то еще. Я попытался упростить его в этом примере (http://ideone.com/bjQ1s8), но в моей реальной программе независимо от индекса, который я использую с указателями класса, я не получаю никаких ошибок и все еще работает. –