Ответ 1
Оба (a)
и (b)
приводят к поведению undefined. Всегда undefined поведение вызывает функцию-член через нулевой указатель. Если функция статична, она технически undefined, но есть некоторые споры.
Первое, что нужно понять, - это почему поведение undefined для разыменования нулевого указателя. В С++ 03 здесь есть немного двусмысленности.
Хотя "разыменование нулевого указателя приводит к поведению undefined" упоминается в примечаниях как в §1.9/4, так и в § 8.3.2/4, оно никогда явно не указано. (Примечания не являются нормативными.)
Однако можно попытаться вывести его из § 3.10/2:
Значение l относится к объекту или функции.
При разыменовании результат равен lvalue. Нулевой указатель не относится к объекту, поэтому, когда мы используем lvalue, мы имеем поведение undefined. Проблема в том, что предыдущее предложение никогда не указано, так что значит "использовать" значение lvalue? Просто даже создайте его вообще или используйте его в более формальном смысле преобразования lvalue-to-rvalue?
Несмотря на это, он определенно не может быть преобразован в rvalue (§4.1/1):
Если объект, к которому относится lvalue, не является объектом типа T и не является объектом типа, производного от T, или если объект не инициализирован, программа, которая требует этого преобразования, имеет поведение undefined.
Здесь это определенно поведение undefined.
Неоднозначность исходит из того, относится ли поведение undefined к уважению, но не использует значение из недопустимого указателя (то есть получает значение lvalue, но не преобразует его в rvalue). Если нет, то int *i = 0; *i; &(*i);
четко определен. Это активная проблема .
Таким образом, у нас есть строгий "разыменовать нулевой указатель, получить представление" w90 > поведение "и" слабый "использовать разыменованный нулевой указатель, получить представление" w90 > поведение ".
Теперь рассмотрим вопрос.
Да, (a)
приводит к поведению undefined. Фактически, если this
равно null, то независимо от содержимого функции результат равен undefined.
Это следует из п. 5.2.5/3:
Если
E1
имеет тип "указатель на класс X", то выражениеE1->E2
преобразуется в эквивалентную форму(*(E1)).E2;
*(E1)
приведет к поведению undefined со строгой интерпретацией, а .E2
преобразует его в значение r, что делает его undefined для слабой интерпретации.
Отсюда также следует, что поведение undefined непосредственно из (§9.3.1/1):
Если нестатическая функция-член класса X вызывается для объекта, который не относится к типу X или типа, полученного из X, поведение undefined.
Со статическими функциями строгая и слабая интерпретация делает разницу. Строго говоря, это undefined:
Статический член может ссылаться на использование синтаксиса доступа к члену класса, и в этом случае оценивается объектное выражение.
То есть, он оценивается так же, как если бы он был нестатическим, и мы снова разыменовали нулевой указатель с помощью (*(E1)).E2
.
Однако, поскольку E1
не используется в статическом вызове функции-члена, если мы используем слабую интерпретацию, вызов корректно определен. *(E1)
приводит к lvalue, статическая функция разрешена, *(E1)
отбрасывается, и функция вызывается. Нет преобразования lvalue-to-rvalue, поэтому не существует поведения undefined.
В С++ 0x, начиная с n3126, остается неопределенность. Пока что будьте в безопасности: используйте строгую интерпретацию.