Странное поведение нулевого указателя

Я создал указатель NULL класса App, но каким-то образом метод объекта NULL (приложения) работает. Вот мой код:

#include "App.h"
#include <iostream>
using namespace std;
int main()
{
    App* pointer = NULL;
    pointer->print();

    system("pause");
}

Прикрепил файл заголовка

#pragma once
#include <iostream>
using namespace std;
class App
{
private:
    int x;
    int y;
public:
    App(void);
    ~App(void);
    App(int a, int b)
    {
        x=a;
        y=b;
    }
    void print()
    {
        cout<<"hello world"<<endl;
    }
};

Результат бега на экране: hello world. Это почему?


person benny perl    schedule 25.04.2013    source источник
comment
Попробуйте использовать одну из переменных-членов в функции, и что-то может случиться.   -  person Some programmer dude    schedule 25.04.2013


Ответы (6)


Неопределенное поведение и есть неопределенное. Все может случиться, включая видимость правильного поведения.

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

person Carl Norum    schedule 25.04.2013
comment
Но почему? нет логического объяснения? - person benny perl; 25.04.2013
comment
Вам нужно будет посмотреть, что сделал ваш компилятор, чтобы понять это (см. Мой второй абзац). Боюсь, в вашем вопросе недостаточно информации для того, чтобы мы продолжали это делать. - person Carl Norum; 25.04.2013
comment
@bennyperl Вы также можете заметить, что компилятор рассматривает методы как относительно стандартные вызовы функций, которые просто передают указатель this через регистр или как первый аргумент. Поскольку рассматриваемая функция не обращалась к this, она не заметила бы nullptr this. Поскольку в стандарте C ++ указано, что вы делаете неопределенное поведение, компилятор может генерировать код, который делает все, что захочет - segfault, форматирование жесткого диска, отправка информации о вашем банковском счете в Aruba - или, в данном случае, игнорирование указатель this равен nullptr. Полагаться на это - плохая идея. - person Yakk - Adam Nevraumont; 25.04.2013
comment
+1 @Yakk - хорошее объяснение. - person Carl Norum; 25.04.2013
comment
@bennyperl: Невозможно переоценить тот факт, что неопределенное поведение означает, что не может быть никакого логического объяснения: все может случиться, включая форматирование вашего жесткого диска или взрыв луны. Любое логическое объяснение, вероятно, будет правильным только на ограниченном количестве платформ и ошибочным на большом количестве других платформ (даже один и тот же исполняемый файл может вести себя по-разному в разных версиях ОС, если задействован UB!). Пытаться урезонить UB бесполезно, единственное, что вы можете сделать разумно, - это избежать его срабатывания. - person syam; 25.04.2013

Разыменование указателя NULL является неопределенным поведением. Вы не должны ожидать, что ваша программа не будет «работать» только потому, что вы это сделаете.

В этом случае ваша функция печати не «использует» указатель this, поэтому ваш код выполняется так, как вы ожидали. Но не стоит полагаться на это, неопределенное поведение означает именно то, что написано.

person john    schedule 25.04.2013

Вызов метода для указателя NULL является неопределенным поведением, поэтому может случиться что угодно. Никогда не следует рассчитывать на то, что код всегда будет производить такой вывод. Всегда старайтесь избегать таких ситуаций.

person Ivaylo Strandjev    schedule 25.04.2013

Это неопределенное поведение. Реализация может работать в этом игрушечном примере, потому что print не имеет доступа к переменным-членам и не является виртуальной функцией.

person Mark Borgerding    schedule 25.04.2013

Это неопределенное поведение, это thread объясняет, почему это, скорее всего, работает, основное объяснение состоит в том, что он, вероятно, будет преобразован во что-то похожее на:

void _App_print( App* this ); 

и поскольку вы не используете this, он работает.

person Shafik Yaghmour    schedule 25.04.2013

Потому что print (даже неявно) не обращается к каким-либо данным за указателем this.

person oseiskar    schedule 25.04.2013