Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Непонятки с укзателями, delete и памятью вообще


Автор: RenderMan 8.12.2008, 23:17
Решил поиздеваться над компилятором: 
Код

int main()
{
    int* a= new int(1);
    cout << *a << endl;
    delete a;
    *a =5; // я думал, что сдесь произойдет ошибка выполнения
    cout << *a << endl;
    return 0;
}



не ту-то было, ошибки не произошло, что вообще логично, т.к. указатель указывает на какую-то область памяти, и мы вправе делать с этой памятью все, что захотим(или нет?).

Теперь немного модифицируем код:
Код

int main()
{
    int* a= new int(1);
    cout << a << endl;
    delete a;
    *a =5;
    //ADDED------>>>>>
    int* b = new int(4);
    return 0;
}




теперь программа ругается(SIGSEGV). Еще немного изменим код:
Код

int main()
{
    int* a= new int(1);
    cout << a << endl;
    delete a;
    //*a =5;
    //ADDED------>>>>>
    int* b = new int(4);
    cout << b << endl;
    return 0;
}

на консоль выводятся одинаковые числа, т.е. выделяется одна и та же память. Но почему проге все нравится, пока я делаю,что хочу с НЕПРИНАДЛЕЖАЩЕЙ ей памятью , а потом, когда мы выделяем ей совершенно легально ту самую память, она начинает ругаться? Каким образом куча узнает, что я что-то делал со свободной памятью, или она ведет какой-то ее мониторинг? Хочу обратить внимание,что крэш идет именно на выделении памяти под b.  Или может быть так,что,например, куча считает,что это нрмальная ячейка памяти, но когда она(куча) просит ее выделить у системы, та ей говорит, что, мол, только что к ней обращялись, и поэтому я тебе эту память не отдам.
Разъясните, пожалуйста, по-моему, это важный вопрос.

Автор: Dmi3ev 9.12.2008, 01:03
Цитата

    *a =5; // я думал, что сдесь произойдет ошибка выполнения

Почему?
Цитата

delete a;

Мы освобождаем участок памяти, адрес которой хранится в указателе, но указатель остается, мы его-то не удаляем никуда, можем поменять адрес.
И чего тут такого великого???

Автор: J0ker 9.12.2008, 05:52
Цитата(RenderMan @  8.12.2008,  23:17 Найти цитируемый пост)
не ту-то было, ошибки не произошло

это вам просто повезло

Цитата(RenderMan @  8.12.2008,  23:17 Найти цитируемый пост)
что вообще логично, т.к. указатель указывает на какую-то область памяти

любой указатель указывает на какую-то область памяти
с вышеозначеным явлением это никак не связано

Цитата(RenderMan @  8.12.2008,  23:17 Найти цитируемый пост)
и мы вправе делать с этой памятью все, что захотим(или нет?)

или нет

Цитата(RenderMan @  8.12.2008,  23:17 Найти цитируемый пост)
теперь программа ругается(SIGSEGV)

это не программа ругается, а процессор

дальнейший бред не понят, сорри  smile 

Автор: MAKCim 9.12.2008, 09:48
Цитата(J0ker @  9.12.2008,  05:52 Найти цитируемый пост)
это не программа ругается, а процессор

процессор SIGSEGV'ами не ругается  smile 

Автор: ksili 9.12.2008, 10:02
Что такое SIGSEGV я не знаю, но думаю дело такое:

В первом коде память освобождена и пока никем не занята, ук-ль a указывает на неё, т.к. его значение не изменилось, через него работаем с этой памятью

Во втором коде память освобождена, потом выделена заново, и получилось, что a указывает уже на чужую память, а не на свободную или свою. Видимо поэтому и произошла ошибка.

В третьем случае, ничего непонятного. Просто получилось так, что b выделилось на месте a. Просто совпадение.

Автор: mes 9.12.2008, 10:07
Цитата(ksili @  9.12.2008,  10:02 Найти цитируемый пост)

Во втором коде память освобождена, потом выделена заново, и получилось, что a указывает уже на чужую память, а не на свободную или свою. Видимо поэтому и произошла ошибка.

нет.. во всех случаях просто совпадение. Система не всегда может определить запись программы не в "свою" память - один и тот же пример в разных контекстах может давать разный результат. 

Автор: Dmi3ev 9.12.2008, 13:38
RenderMan, в принципе можно разбить молотком монитор и радоваться тому, что можешь делать все что угодно не только с памятью, но и с монитором  smile 
А можно пойти и дальше, выйти во двор и разбить лобовое стекло первому попавшемуся автомобилю и радоваться тому, что ты можешь делать все что угодно и с ним  smile
Главное думать о последствиях  smile 
Все, что ты делаешь обязательно приведет к проблемам, даже если это все прокатило на твоем компиляторе, если твоя программа будет немного длиннее и функциональнее  smile
Вообщем, повелитель памяти... Попробуй сделать прогу на основе своих извращений и все станет ясно... 

Автор: xvr 9.12.2008, 14:32
Все очень просто: когда ты сделал int* a= new int(1); crt выделила кусок памяти и вернула его адрес, который затем попал в a. Реальный размер выделенного участка, а равно как и его реальное начало в памяти, не обязаны совпадать с тем, что ты запрашивал. Скорее всего, будет выдеден блок байт так в 8-16, и перед a еще будет байт 8 с размером выделенного участка.
Затем ты делаешь delete a;, память, ранее занимаемая этим блоком, возвращается в пул свободной памяти. При этом этот блок провязывается в списки свободной памяти, для указателей этих списков используется тело блока (это можно сделать, т.к. приложение аернуло эту память, и crt имеет право распоряжаться ей по своему усмотрению)
Затем, ты делаешь *a =5;, перезаписывая таким образом один из указателей списка свободной памяти своей 5кой. Список свободных блоков разрушен  smile  Последующий вызов int* b = new int(4); приведет к краху менеджера памяти, когда он попытается найти свободный блок, обходя список этих блоков по разрушеннему списку, что ты и получил в виде SIGSEGV

Автор: J0ker 9.12.2008, 19:03
Цитата(MAKCim @  9.12.2008,  09:48 Найти цитируемый пост)
процессор SIGSEGV'ами не ругается

процессор ругается протекшен-фолтами, которые транслируются ОС в SIGSEGV
ты удовлетворен?  smile 

Автор: RenderMan 9.12.2008, 21:33
Извращался я не потому что писал прогу, а хотел понять механизм выделения памяти с помощью крэшей). Весь вопрос собственно заключался в следующем: каким макаром мех-изм выделения памяти узнает,что я что-то делал со свободной памятью. по-моему, xvr все объяснил, за что ему отднльная благодарность).  Всем спасибо)

Автор: taiven 11.12.2008, 02:01
Цитата(RenderMan @  8.12.2008,  22:17 Найти цитируемый пост)
Решил поиздеваться над компилятором: 

вот это мне кажется поинтересней будет  smile 
Код

    int *a = new int(1);
    int *b = a;
    delete a;

    int *c = new int(5);

    delete b;

    int *d = new int(10);

    std::cout << "c = " << *c << '\n';

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)