2012-01-31 4 views
0

поэтому я выполняю этот кодУдаление массив символов, кажется, не влияет на массив на всех

#include <cstdlib> 
#include <iostream> 
int main() 
{ 
    char *test = new char[10]; 
    strcpy(test, "Hello Ther");; 
    std::cout << test << std::endl; 
    delete[] test; 
    std::cout << test << std::endl; 
    return 0; 
} 

и выход

Здравствуйте Ther

Здравствуйте Ther

Кажется, что заявление delete[] test ничего не делает ... Нет runti я или ошибки компиляции время на всех

полностью озадачен мне

+2

Как вы думаете, 'delete []' должен делать то, что это не так? –

+6

[Ваша Библия не была затронута] (http://stackoverflow.com/a/6445794/596781) - посчитайте себя счастливым. –

+0

Исправить ошибку в коде, и проблема исчезнет. (Например, переместите элемент 'delete' после последнего вывода.) –

ответ

8

После вас delete[] массив, нет более массива. Любой доступ через этот указатель после этого имеет неопределенное поведение.

delete[] предполагается вызвать деструкторы на элементах массива и освободить используемое им хранилище. Поскольку char не имеет деструктора, он просто освобождает хранилище. Освобождение памяти означает, что она больше не используется.

FWIW, в вашем коде есть еще один случай неопределенного поведения. "Hello Ther" имеет 11 элементов: в конце есть терминатор ('\0'). strcpy В том, что в буфер только 10 элементов большой, это неопределенное поведение. Вам нужен буфер с пространством для 11 элементов: 10 символов «Hello Ther» плюс нулевой терминатор.

Эта ошибка, переполнение буфера, является распространенным источником уязвимостей безопасности. С по крайней мере в 1980-х годах были известны такие ошибки такого рода ошибок. Было бы разумно избегать таких небезопасных примитивов и предпочитать безопасные современные (и «современным» я имею в виду «с 1990-х годов»), например std::string. Потому что, знаете, это 21-й век.

3

Что вы ожидали?

Когда вы удаляете указатель, все, что происходит, это память, предоставленная вам, когда вы вызывали новое, была возвращена системе. Если вы не выделите или не коснитесь памяти в любом случае после того, как вы вызвали удаление (как в вашем примере), старое содержимое памяти по-прежнему, вероятно, будет зависеть. Было бы хитом производительности для удаления, чтобы все равно потерять всю эту память (некоторые отладочные сборки компилятора записывают специальные значения в delete, чтобы облегчить поиск недопустимого доступа к памяти). Если вы поехали и коснулись памяти, выделив больше памяти или вызвав функцию, значение может быть уничтожено. Хотя это может и не быть, поэтому доступ к указателю после удаления называется неопределенным поведением.

2

В C++ можно получить доступ к памяти независимо от того, выделено ли оно или нет. Это вызывает неопределенное поведение, но нет никакой проверки, которая говорит, является ли данная память «доступной». Это твоя проблема. Это контрастирует с языками на основе VM, где доступ к памяти проверяется для вас.

Обычным идиом, чтобы избежать такого рода ошибки, чтобы сделать это:

delete[] myArray; 
myArray = NULL; // preferably "nullptr" in C++11 

Любой доступ к NULL адреса отказался от CPU. Он будет предупреждать ОС об ошибке (что, скорее всего, закончит вашу программу с ошибкой segfault или эквивалентной).

Как упоминалось stonemetal, некоторые компиляторы/операторы/распределители будут проверять доступ к памяти в отладочных сборках, но не будут делать это в режиме освобождения для увеличения скорости.

Примечание. Если вы попытаетесь получить доступ к нераспределенной памяти случайным образом, вы столкнетесь с ошибками страницы, но это немного не по теме.