В достоинство ссылок ставиться то, что они всегда ссылкаются на объект. Однако это не так, то есть не совсем так. Мы живем не в идеальном мире и наши инструменты тоже не идеальны.
Синтаксические правила требуют всегда инициализиировать ссылки объектами, на которые они будут ссылаться. И, казалось бы, этого достаточно чтобы гарантировать валидность ссылки. Но объекты в C++ могут иметь разное время жизни и располагаться в разных областях памяти. И если ссылка ссылается (простите за тавтологию) на объект в динамической памяти (выделенный с помощью malloc, new или других аллокаторов) или на объект лежащий в стэке, то компилятор не может проверить валидность объекта во время компиляции.
Пример:
Тут все еще существует ссылка, но память, в который хранился объект, освобождена и возможно уже выделена другим потоком, поэтому r ссылается теперь не понятно на что. Аналогинчая ситуация с new/delete.
Можно придумать множество похожих ситуаций. Все ситуации объединяет, то что ссылка изначально была валидной, но объект был уничтожен, а ссылка — нет.
Но бывают ситуации, когда ссылка не является валидной изначально.
Этот пример компилируется и запускается на доступных мне компиляторах GCC 4.2 и MSVS 2005. Думается, аналогичная ситуация будет в остальных.
При попытке обратиться к объекту, на который ссылается ссылка, получаем Segmentation fault. Это происходит потому, что компиляторы реализуют ссылки на динамические объекты по средством константных указателей, которые могут содержать NULL, и не проверяют значение в целях оптимизации, оставляя это на совесть программиста.
Синтаксические правила требуют всегда инициализиировать ссылки объектами, на которые они будут ссылаться. И, казалось бы, этого достаточно чтобы гарантировать валидность ссылки. Но объекты в C++ могут иметь разное время жизни и располагаться в разных областях памяти. И если ссылка ссылается (простите за тавтологию) на объект в динамической памяти (выделенный с помощью malloc, new или других аллокаторов) или на объект лежащий в стэке, то компилятор не может проверить валидность объекта во время компиляции.
Пример:
int *p = (int*)malloc( sizeof(int) );
int &r = *p;
free( p );
// r – все еще доступна
Тут все еще существует ссылка, но память, в который хранился объект, освобождена и возможно уже выделена другим потоком, поэтому r ссылается теперь не понятно на что. Аналогинчая ситуация с new/delete.
Можно придумать множество похожих ситуаций. Все ситуации объединяет, то что ссылка изначально была валидной, но объект был уничтожен, а ссылка — нет.
Но бывают ситуации, когда ссылка не является валидной изначально.
#include <stdio.h>
int* genptr() {
return NULL; // код, который потенциально может венуть NULL.
}
int main() {
int& r = *genptr();
printf( "%p\n", &r );
printf( "%i\n", r ); // Segmentation fault
return 0;
}
Этот пример компилируется и запускается на доступных мне компиляторах GCC 4.2 и MSVS 2005. Думается, аналогичная ситуация будет в остальных.
При попытке обратиться к объекту, на который ссылается ссылка, получаем Segmentation fault. Это происходит потому, что компиляторы реализуют ссылки на динамические объекты по средством константных указателей, которые могут содержать NULL, и не проверяют значение в целях оптимизации, оставляя это на совесть программиста.