2010-10-13 3 views
1

Предположим, у меня есть класс, какКогда возникает segfault?

class A { 
    int x; 
    int y; 
    public: 
    getSum1() const { 
     return getx() + y; 
    } 
    getSum2() const { 
     return y + getx(); 
    } 
    getx() const { 
     return x; 
    } 
} 

И тогда я

int main(int argc, char **argv) { 
    A *a = 0; 
    switch(argc) { 
    case 0: 
     a->getsum1(); 
     break; 
    default: 
     a->getsum2(); 
     break; 
    } 
    return 1; 
} 

Эта программа Segfault. Я заметил, что на моей машине, когда getum1 выполняется, ядро ​​ указывает, что segfault был вызван в getx, и когда getsum2 выполняет его, он говорит, что ошибка произошла в getum2.

Это имеет смысл. У меня есть 2 вопроса:
1. Это поведение указано или зависит от реализации?
И самое главное:
2. Может ли основной дамп сказать, что segfault произошел в основном, когда был разыменован? (т. е. при a-> getsum *)

Спасибо.

+0

Duplicate-ish? http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-behav – GManNickG

ответ

1

Когда вы вызывали эти функции по нулевому указателю, вы получили undefined behavior. Это действительно все, что нужно сказать; все может случиться, не делайте этого.

Причина, по которой это происходит, потому что нет A при нуле. Попытка доступа к этим членам пытается получить доступ к недействительному адресу. (Это происходит в getx и getSum2, поэтому отчет выдаёт ошибку сегментации.)

Нет, он не может сказать, что произошло в выдаёт ошибку сегментации main, поскольку нуль не обращались в основном. (Вы по-прежнему вводили неопределенное поведение в принципе, без сомнения, но на практике он просто вызвал функцию с this, установленным в null.) Вы получили доступ к ней в этих функциях. На практике, если функция никогда не использует this, она не будет сбой с нулевым указателем.

Но нет.

+0

Если функция не использует 'this' то в любом случае это должно быть «статическим». –

+0

@ Питер Александр: Технически да, это может быть статическая погода, которая должна сильно зависеть от контекста. Лично я ненавижу, что абсолютное программирование правил так много о текущих ситуациях, что жесткие и быстрые правила делают код уродливым. Поэтому я бы сказал, что метод, который не использует каких-либо членов, должен быть учтен (очень высок в списке) для превращения в статический метод. –

0

Вызов доступа к элементам и вызовам функций-членов в нулевых указателях является неопределенным поведением.

Segfault происходит, когда программа пытается получить доступ к x или y, поэтому это происходит в getx() в первом и getSum2() во втором.

0

К тому времени, когда coredump происходит, вы больше не находитесь на C++. Некоторые утверждения в скомпилированном коде вызвали плохие вещи, например попытку доступа к недопустимому адресу памяти, в вашем случае с помощью нулевого указателя.

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

Дело в том, что возврат из скомпилированных двоичных файлов в строки источника является несколько сложным, потому что в языке имеется множество возможностей для определенного «как-будто» вида переупорядочения высказываний и другой умности.

Итак, сам C++ в спецификации языка не укажет, что скажет вам основной дамп, и, как уже было замечено, явно дает недофинансированное поведение при удалении ссылок на нулевые указатели.

Дело в том, что я действительно не думаю, что это слишком важно. Для такого рода ошибок получается «достаточно близкий» показатель того, где проблема вскоре приводит к источнику проблемы.Далекие неприятности - это проблемы с кучеобразованием, возникающие там, где симптом и причина могут быть много шагов удалены друг от друга, а отвалы ядра меньше используются.

0

Две важные вещи:

  1. Вы неопределенное поведение, потому что a является недействительным. Неопределенное поведение означает, что все идет, стандарт C++ не налагает ограничений на программу с неопределенным поведением.

  2. Порядок оценки операндов для арифметических операторов: не указан. Это означает, что компилятор может генерировать код, который вызывает getX() сначала в обеих из двух функций getSum, даже если вы заказывали их по-разному. В вашем конкретном случае порядок оценки операндов согласован.

    § 5/5 “ ” выражения: Если не указано иное, порядок оценки операндами отдельных операторов и подвыражениям отдельных выражений, и порядок, в котором побочные эффекты имеют место, не определен.

0

"Когда брошен выдаёт ошибку сегментации?" Иногда бывает никогда брошен, когда нужно бросить. Основание большая реализация - это система операций с защита памяти. Когда ОС отсутствует (встроен) или очень просто (CP/M, DOS) или имеет «низкий профиль» (встроенный), или у ЦП нет такой функциональности (< 80186) проблема скрыта или отложена. Это очень плохая новость. Хьюстон, у нас БОЛЬШАЯ невидимая проблема.

Примечание: C++ в защищенной среде можно реализовать сценарии, когда проблема скрыта тоже (указатель плохо, но в действительной области)

Общее правило, как понимать C/C++ является ключевым «неопределенное поведение» (как и многие ответы), иногда такое исключение

Смежные вопросы