В следующем коде:
int main(int argc,char * argv[]){
int * ptr;
ptr = 0; // tried also with NULL , nothing changes
ptr = new int[10]; // allocating 10 integers
ptr[2] = 5;
ptr[15] = 15; // this should cause error (seg fault) - but it doesn't
cout << ptr[2] << endl;
cout << ptr[15] << endl; // no error here
delete [] ptr;
cout << ptr[2] << endl; // prints the value 5
cout << ptr[15] << endl; // prints the value 15
}
Результат выполнения:
5 15 5 15
Я попытался удалить с одним выделением, как это:
int * ptr;
ptr = 0;
ptr = new int;
*ptr = 5;
cout << *ptr << endl;
delete ptr ;
cout << *ptr << endl;
Результат нормальный:
5 0
Протестировано с gcc 4.7.2 и gcc 4.1.2 на fedora 17 и другой платформе (SLC5 — Linux на основе Red Hat), чтобы убедиться, что она не зависит от компилятора. Что я здесь не так делаю?
Элемент за пределами заданного размера массива существует, потому что память там существует. Делать что-либо с этим незаконно и приводит к неизвестности.
Освобождение означает, что память больше не выделена для вас. Это не значит, что кто-то пошел туда и почистил. Но доступ к тому, что от вас осталось, является незаконным и ведет к неизвестному.
Вы обращаетесь к памяти, которая не принадлежит массиву. Это работает из-за чистой удачи. Если программа не дает сбоя, это означает, что вы перезаписываете части памяти, которые принадлежат вашему собственному приложению, и, таким образом, вы что-то разрушаете, и больше нельзя гарантировать, что ваша программа работает правильно.
В основном вы получите ошибку сегментации, потому что вы обращаетесь к памяти других приложений. На этот раз вам просто «повезло». Или, как я бы назвал, «неудачным», потому что вы не можете сразу сказать из исполнения, что ваша программа имеет ошибки памяти.
Разыменование удаленного указателя является неопределенным поведением, как определено стандартом C ++. И это только неопределенное поведение. Вы можете потерпеть крах, вы можете получить 0, вы можете получить то, что было там ранее, или 42. В этом месте по определению нет «нормального» поведения.