2010-07-15 1 views
7

я наткнулся на следующий код недавно:Является ли это законным/четко определенным C++ для вызова нестатического метода, который не имеет доступа к элементам через нулевой указатель?

class Foo 
{ 
public: 
    void bar(); 
    // .. other stuff 
}; 

void Foo::bar() 
{ 
    if(!this) { 
     // .. do some stuff without accessing any data members 
     return; 
    } 

    // .. do normal actions using data members 
} 

Код компилируется, потому что методы в C++ просто функции, которые неявно передается указатель на «это» и «это» может быть проверен, чтобы быть NULL, как и любой другой указатель. Очевидно, что этот код запутан и плох, даже если он не падает; было бы довольно сложно переходить через код в отладчике, см. указатель NULL, который должен вызвать метод, вызываемый на нем, а затем не увидеть ожидаемый сбой. Мой вопрос: нарушает ли стандарт C++ вызов SomeFooPtr->bar(), где SomeFooPtr == NULL?

Мне кажется, что это не так, потому что пользователь определил operator-> возвращает указатель, а это означает, что даже если этот указатель имеет значение NULL, он определенно не был разыменован (разыменование указателя NULL, я уверен, считается по стандарту, как незаконный или неопределенный). С другой стороны, семантика исходных указателей необязательно должна соответствовать семантике определяемых пользователем указателей - возможно, оператор-> на них считается разыменованием, даже если компилятор не будет генерировать его.

+0

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

ответ

13

Это, вероятно, будет работать на большинстве систем, но это неопределенное поведение. Каркнул стандарт:

5.2.5.3

Если E1 имеет тип «указатель на класс X,» то выражение E1->E2 преобразуется в эквивалентную форму (*(E1)).E2 [...]

А:

5.2.5.1

Постфиксное выражение, за которым следует точка . или стрелка ->, необязательно с последующим ключевым словом template (14.8.1), а затем последующее выражение является постфиксным выражением. Вычисляется постфиксное выражение перед точкой или стрелкой; 58) [...]

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

Оценка *x где x является нулевым результатом указателя неопределенного поведения, так что ваша явно случай UB, прежде чем функция даже вошла.

+0

Спасибо, это точно что я искал. –

+0

Извините за грязные изменения. Сначала я пропустил что-то в Стандарте, тогда я неправильно понял ваш вопрос. Теперь все должно быть хорошо. – Thomas

+0

Не могли бы вы привести пример выражения формы 'A.template B'? Где этот синтаксис имеет значение? – Philipp

1

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

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

1

Это (все вместе сейчас) undefined поведение. Однако для многих компиляторов он будет работать с дополнительным ограничением того, что метод должен быть не виртуальным.

1

Это UB. Хорошим способом сделать это сбоем является использование его в качестве базового класса производного класса, который использует множественное наследование. YMMV.

7

Этот тест не работает, даже если разыменование не было UB. Он ломается, когда в настройку входят такие корректировки для множественного наследования:

#include <stdio.h> 
class B 
{ 
    int value; 
    public: 
    void foo() 
    { 
     if (!this) 
      printf("this==0\n"); 
     else 
      printf("safe\n"); 
    } 
}; 
class A { public: int anotherValue; }; 
class Z : public A,public B {}; 

int main() 
{ 
    Z *z=0; 
    z->foo(); 
} 

печатает «безопасный» здесь.

+0

Отличный пример! Благодарю. – Vlad

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

  • Нет связанных вопросов^_^