Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.
Пример:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Вы можно просто избежать этого, проверив, является ли переменная не нулевой:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .
Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!
Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.
Типы ссылок (эти должны быть проверены):
Типы значений (вы можете просто игнорировать эти):
Из C99 Standard (акцент мой)
6.5.3.4/2
Оператор sizeof дает размер (в байты) его операнда, который может быть выражением или заключенным в скобки именем типа. Размер определяется по типу операнда. Результат - целое число. Если тип операнда - тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат является целочисленной константой.
blockquote>
Выполнение не может произойти во время компиляции. Поэтому ++i
/ i++
не будет. Также sizeof(foo())
не будет выполнять функцию, но вернет правильный тип.
Поскольку операнд оператора sizeof
не оценивается, вы можете сделать это:
int f(); //no definition, which means we cannot call it
int main(void) {
printf("%d", sizeof(f()) ); //no linker error
return 0;
}
Демо-версия онлайн: http://ideone.com/S8e2Y
То есть вам не нужно определять функцию f
, если она используется только в sizeof
. Этот метод в основном используется в метапрограммировании шаблонов C ++, так как даже в C ++ операнд sizeof
не оценивается.
Почему это работает? Он работает, потому что оператор sizeof
не работает с значением , вместо этого он работает с типом выражения. Поэтому, когда вы пишете sizeof(f())
, он работает с типом выражения f()
, и это не что иное, как возвращаемый тип функции f
. Тип возврата всегда один и тот же, независимо от того, какое значение возвратит функция, если оно действительно выполняется.
В C ++ вы можете даже это:
struct A
{
A(); //no definition, which means we cannot create instance!
int f(); //no definition, which means we cannot call it
};
int main() {
std::cout << sizeof(A().f())<< std::endl;
return 0;
}
Однако похоже, в sizeof
я сначала создаю экземпляр A
, записывая A()
, а затем вызывая функцию f
в экземпляре, написав A().f()
, но такого не происходит.
Демо: http://ideone.com/egPMi
Вот еще одна тема, которая объясняет некоторые другие интересные свойства sizeof
:
sizeof
является встроенным оператором компиляции и не является функцией. Это становится очень ясным в тех случаях, когда вы можете использовать его без скобок:
(sizeof x) //this also works
sizeof(foo)
действительно пытается обнаружить размер выражения во время компиляции:
6.5.3.4:
Оператор sizeof дает размер (в байтах) ) его операнда, который может быть выражением или заключенным в скобки именем типа. Размер определяется по типу операнда. Результат - целое число. Если тип операнда - тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат является целочисленной константой.
blockquote>Короче: массивы переменной длины, выполняемые во время выполнения. (Примечание: Массивы переменной длины - это определенная функция - не массивы, выделенные с помощью
malloc(3)
.) В противном случае вычисляется только тип выражения и что при компиляции время.
sizeof()
дает размер только типа данных, он не оценивает внутренние элементы.