NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Похоже, что Visual Studio
просто не работает в отношении того, какой конструктор он вызывает, когда аргумент по умолчанию представляет собой список инициализатора . Этот код:
#include <iostream>
struct test {
test () { std::cout << "test ()" << std::endl ; }
test (int) { std::cout << "test (int)" << std::endl ; }
};
void func( test const &s = {} )
{
}
int main()
{
test s = {} ;
func() ;
}
производит этот результат в gcc
и clang
, смотрите его здесь :
test ()
test ()
, в то время как Visual Studio
производит это результат:
test ()
test (int)
и для этого кода:
#include <iostream>
#include <initializer_list>
struct test {
test () { std::cout << "test ()" << std::endl ; };
test (int) { std::cout << "test (int)" << std::endl ; };
test ( std::initializer_list<int>) { std::cout << "test (initializer_list<int>)" << std::endl ; } ;
};
void func( test const &s = {0} )
{
}
int main()
{
test s = {0} ;
func() ;
}
gcc
и clang
дают этот результат, смотрите в прямом эфире здесь :
test (initializer_list<int>)
test (initializer_list<int>)
, в то время как Visual Studio
выдает эту ошибку:
error C2440: 'default argument' : cannot convert from 'initializer-list' to 'const test &'
Reason: cannot convert from 'initializer-list' to 'const test'
No constructor could take the source type, or constructor overload resolution was ambiguous
Обновление
Для проверки работоспособности я вернулся к стандарту, чтобы убедиться, что там не было каким-то странным правилом, лежащим в основе этого различия, или, возможно, каким-то ограничением, делающим этот код некорректным . Насколько я могу судить, этот код не является неправильно сформированным . Грамматика секции 8.3.5
специально позволяет это:
parameter-declaration:
attribute-specifier-seqopt decl-specifier-seq declarator
attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
[...]
Это не похоже на секции 8.5
Инициализаторы или 8.3.6
Аргументы по умолчанию добавляют любые ограничения, но отчет об этом дефекте 994. braced-init-list в качестве аргумента по умолчанию и рабочий документ Формулировка скобочных инициализаторов в качестве аргументов по умолчанию проясняет, что он был задуман, и обрисовывает в общих чертах изменения, внесенные в стандарт, чтобы позволить его и смотреть В дельтах нет явных ограничений.