2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Работа с памятью в с++
Сообщение11.11.2012, 16:56 


11/06/12
20
Добрый день! Не так давно начал программировать на с++, есть несколько вопросов по работе с памятью:
1. Можно ли удалять объекты из стека? (также как удаление объектов из кучи)
2. Что происходит при вызове деструктора для объекта в стеке
Код:
MyClass a = MyClass();
a.~MyClass();

3.Delete, насколько я понимаю, возвращает память операционной системе, и мы не должны иметь ней доступ из программы, тогда что мы получает по указателю после delete?

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 17:11 


15/03/11
137
Mr Alexey в сообщении #643042 писал(а):
3.Delete, насколько я понимаю, возвращает память операционной системе, и мы не должны иметь ней доступ из программы, тогда что мы получает по указателю после delete?

По идее, мы получаем тоже, что и до delete. Другое дело, что если ты "вернул память", то ты должен проконтролировать сам, чтобы к ней больше не обращаться.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 17:38 


11/06/12
20
zhekas в сообщении #643062 писал(а):
По идее, мы получаем тоже, что и до delete. Другое дело, что если ты "вернул память", то ты должен проконтролировать сам, чтобы к ней больше не обращаться.

Не думаю, что мы получаем тоже - поля класса до и после различаются.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 17:41 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Mr Alexey в сообщении #643042 писал(а):
1. Можно ли удалять объекты из стека? (также как удаление объектов из кучи)

Память в стеке выделяется не так, как в куче, не произвольно, а последовательно. Когда в стеке выделили память для объектов a и b, то указатель стека указывает на b или свободное место за ним, и память объекта a использовать уже нельзя, даже если она уже не нужна: объект b неперемещаемый (вообще все объекты в памяти неперемещаемые, это нужно для того, чтобы работали указатели). Только когда память объекта b будет освобождена - стек уменьшится - тогда можно будет освободить и память объекта a. Стек напрямую программисту неподконтролен, а управляется языком:
1. При входе в блок (в Си) или при объявлении объекта (в C++) стек увеличивается, и в нём размещается этот объект.
1'. При выходе из блока объект уничтожается (если несколько объектов, то в порядке, обратном порядку создания), после чего стек уменьшается.
2. При вычислении выражений, если требуется сохранить временный результат вычислений, создаётся временный объект, аналогично.
2'. При окончании вычисления выражения этот объект уничтожается.
3. При вызове функции, в стеке размещаются все параметры функции (указатели для параметров, переданных по ссылке, дополнительно указатель this для методов объектов), место для возвращаемого значения, служебная информация (например, адрес возврата), и потом управление передаётся функции. Функция размещает свои локальные переменные как объекты в блоке, по п. 1.
3'. При возврате из функции, возвращаемое значение конструируется из выражения в return, потом управление возвращается в вызывающую функцию, и там вся информация (параметры, возвращаемое значение) уничтожается как временные объекты.
4. При выбросе исключения происходит несколько последовательных возвратов из функций, как в п. 3'. Сам объект-исключение при этом находится не в стеке, а то бы стек нельзя было освободить.

Mr Alexey в сообщении #643042 писал(а):
2. Что происходит при вызове деструктора для объекта в стеке

Ничего хорошего, потому что полностью это выглядит так:
    Используется синтаксис C++
    {   // начало блока
        MyClass a = MyClass();   // объявление, выделение памяти в стеке, вызов конструктора для объекта
            // (или даже двух конструкторов - для временного объекта, и копирующего)
        a.~MyClass();   // вызов деструктора для объекта
    }   // конец блока, язык пытается вызвать деструктор для объекта a перед освобождением памяти
        // второй вызов деструктора для невалидного объекта может привести к катастрофе

Mr Alexey в сообщении #643042 писал(а):
3.Delete, насколько я понимаю, возвращает память операционной системе, и мы не должны иметь ней доступ из программы, тогда что мы получает по указателю после delete?

Указатель на свободную память. Обычно там записаны служебные значения исполняющей системы, и если туда чего-нибудь записать своё, то можно испортить кучу программы, и грохнуть её. Вот операционную систему (в хороших ОС) так грохнуть не получится.

Хорошим тоном является записывать 0 в указатель, который освободили.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 18:04 


11/06/12
20
Munin в сообщении #643092 писал(а):
Указатель на свободную память. Обычно там записаны служебные значения исполняющей системы, и если туда чего-нибудь записать своё, то можно испортить кучу программы, и грохнуть её. Вот операционную систему (в хороших ОС) так грохнуть не получится.

А современную систему так грохнуть можно? Вроде Танненбаум писал, что опрационка должна быделять отдельное пространство в памяти для каждого процесса, чтобы такие косяки не происходили.

А при инициализации объектов имеет смысл сначала объявлять более крупные(чтобы располагались внизу стека)? Будет прирост к производительности?

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 18:40 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Mr Alexey в сообщении #643118 писал(а):
А современную систему так грохнуть можно? Вроде Танненбаум писал, что опрационка должна быделять отдельное пространство в памяти для каждого процесса, чтобы такие косяки не происходили.

Вот именно поэтому и нельзя. По крайней мере, Винды серии NT, и Linux/MacOS нельзя. За операционки смартфонов и за Винды серии 95 не скажу.

При возврате куска памяти не от программы к исполняющей системе, а от исполняющей системы к операционке (обычно это делается большими страницами), обычно аппаратно невозможно обратиться по указателю, который раньше на эту память указывал. Программа при такой попытке будет остановлена, типичная диагностика - Segmentation fault, Page fault, Bus error.

Mr Alexey в сообщении #643118 писал(а):
А при инициализации объектов имеет смысл сначала объявлять более крупные(чтобы располагались внизу стека)? Будет прирост к производительности?

Не вижу смысла. Если вы боитесь, что объекты разместятся неудачно, то для объектов в стеке это обычно не играет роли, поскольку функции вызываются мало и стек не перегружен (C++ не настолько провоцирует рекурсию, как языки типа LISP). Это имеет смысл иногда в структурах данных, когда известно, что таких объектов будет размещено в памяти много, например,
может быть лучше, чем
Впрочем, кажется, есть какие-то способы возложить оптимизацию этих вопросов на компилятор, чуть ли не разбиением метками private/public:
    код: [ скачать ] [ спрятать ]
    Используется синтаксис C++
    struct C
    {
    public:
        char a;
    public:
        int b;
    public:
        char c;
    public:
        int d;
    public:
        char e;
    public:
        int f;
    public:
        char g;
    public:
        int h;
    };

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

А объекты в стеке лучше всего размещать в том логическом порядке, в котором они появляются в алгоритме, и могут быть проинициализированы. Используйте идиомы "начальное значение должно устанавливаться инициализацией, а не присвоением" и "выделение ресурса есть инициализация".

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 20:53 
Заслуженный участник


27/04/09
28128
Насчёт размещения полей: мне кажется, уже все современные компиляторы (особенно для C++) имеют по умолчанию включенную опцию выравнивания полей по размерам слова процессора — и это, вроде как, значительнее влияет на производительность, чем расположение полей большей длины перед полями меньшей.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение11.11.2012, 21:55 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Да, я подразумевал, что поля выровнены по словам. Тогда для моего примера будет:
Код:
struct A
|     g |     e |     c |     a |
|                             b |
|                             d |
|                             f |
|                             h |

Код:
struct B
|-------|-------|-------|     a |
|                             b |
|-------|-------|-------|     c |
|                             d |
|-------|-------|-------|     e |
|                             f |
|-------|-------|-------|     g |
|                             h |

то есть 5 слов против 8. Соответственно, миллион таких объектов займёт 20 мегабайт против 32. Да и то, при включённой опции компилятора "упаковывать поля, если можно". В стеке такого не пройдёт, поскольку любой объект занимает место, кратное слову, позиция указателя стека всегда выровнена по словам.

Обращение к объектам A::c, e, g будет происходить с той же скоростью, что и к A::a, гарантированно - и с той же скоростью, что и обращение к A::b, d, f, h. Обращение к структуре в целом может замедлиться, если она окажется длиннее строки кэша какого-нибудь уровня, или будет не выровнена по началам строк кэша - но кэши у процессоров разные, и на всех не наоптимизируешься. Кроме того, кэши часто работают довольно-таки эффективно, то есть там если и потеряется что-то, то крошки, которые нет смысла подбирать.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение12.11.2012, 14:55 


27/03/06
122
Маськва
Mr Alexey в сообщении #643042 писал(а):
Добрый день! Не так давно начал программировать на с++, есть несколько вопросов по работе с памятью:
1. Можно ли удалять объекты из стека? (также как удаление объектов из кучи)

Штатными средствами нельзя: компилятор самостоятельно создаёт там необходимые локальные переменные и следит за их существованием, двигая стек.

Цитата:
2. Что происходит при вызове деструктора для объекта в стеке
Код:
MyClass a = MyClass();
a.~MyClass();

Независимо от того, где находится объект, происходит выполнение этой функции. Ничего более.

Цитата:
3.Delete, насколько я понимаю, возвращает память операционной системе, и мы не должны иметь ней доступ из программы, тогда что мы получает по указателю после delete?

delete только сообщает о том, что мы больше не пользуемся этой памятью. Дальнейшая её судьба для нас не определена.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение13.11.2012, 23:08 
Заслуженный участник


09/09/10
3729

(Оффтоп)

Кстати, кто в курсе, что там за rvalue-references замутили в новом стандарте? Я как в IntelliSense увидел нечто вроде "func(string && Val)", так минут пять пытался вкурить, как это тип AND-ят с... с чем? И почему это происходит в сигнатуре функции?

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение14.11.2012, 00:57 
Заслуженный участник
Аватара пользователя


30/01/06
72407

(Оффтоп)

http://thbecker.net/articles/rvalue_references/section_01.html первая ссылка в гугле. Ахтунг, многабукав, целых 11 страниц текста.

 Профиль  
                  
 
 Re: Работа с памятью в с++
Сообщение14.11.2012, 19:03 
Заслуженный участник


27/04/09
28128

(Оффтоп)

Кошмар, Windows-1252! Я думал, только у нас есть люди, живущие не знаю где. Впрочем, я не совсем против, если бы они проставили кодировку в специальном месте, чтобы браузер не выдумывал её сам.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 12 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group