Справочник по C++
Динамическая память
Если размер объекта или массива заранее неизвестен (например, изображение), или размер объекта слишком большой, чтобы создавать его внутри функции, значит настало время воспользоваться механизмом динамической памяти С++, использующую отдельную область памяти называемой кучей.
Для этого вам необходимо знать всего два оператора:
- new - выделение памяти, если выделение памяти не произошло возвращается нулевой указатель;
- delete - освобождение памяти, не во всех компиляторах после освобождения памяти указателю присваивается 0.
#include <iostream>
using namespace std;
int main() {
// создание объекта типа int со значением 45
// и сохранение его адреса в указателе obj
int* obj = new int(45);
// освободили память на которую указывал obj
cout<<"*obj="<<*obj<<endl;
delete obj;
// елементы массива нельзя инициализировать
// им задается значение по умолчанию
// в случае классов вызывается конструктор по умолчанию
int* array = new int[10];
cout<<"array:";
for(unsigned int i=0; i<10; i++)
cout<<array[i]<<" ";
cout<<endl;
delete [] array;
// для избежания возможных ошибок
// указателю лучше присвоить 0 (при доступе
// к нулевому указателю генерируется системная ошибка,
// а значит ошибка не останется незамеченной)
array=0;
...
}
умные указатели
В С++ нет автоматической сборки мусора. Другими словами, если указатель на выделенную память потерян, то она становится недоступной. Это называется утечкой памяти. Другой крайностью является попытка освободить одну и ту же память более одного раза, что приводит к системной ошибке. Частично или полностью эти проблемы решаются созданием классов, реализующих "умные указатели". Для примера ниже рассмотрены классы из библиотек STL и Boost.
класс auto_ptr
Класс auto_ptr из библиотеки STL имеет следующие ограничения:
- объектом может владеть только один указатель,
- объектом не может быть массив,
- нельзя использовать адресную арифметику.
Единственное предназначение этого класса автоматизировать уничтожение выделенной ранее памяти. Таким образом, данный класс используется, когда время существование выделенного объекта можно ограничить определенным блоком. Аналогичными свойствами обладает и класс scoped_ptr из библиотеки Boost. Но в отличие от auto_ptr для этого класса запрещена передача объекта от одного указателя к другому. Делая код более безопасным, данные классы не наносят ущерб размеру или скорости программы.
#include <memory> // здесь объявление шаблона класса auto_ptr
#include <iostream>
using namespace std;
// Внутри функции мы выделяем память для объекта типа int
// но не освобождаем ее явно оператором delete.
// Это делается автоматически при выходе из функции,
// когда уничтожаются все локальные переменные.
void func() {
auto_ptr<int> aptr(new int(20));
auto_ptr<int> aptr2;
cout<<"*aptr="<<*aptr<<endl;
// следующая строка была бы невозможна при использовании scope_ptr
aptr2=aptr; // теперь aptr не владеет никаким объектом
cout<<"*aptr2="<<*aptr2<<endl;
}
класс shared_ptr
Класс shared_ptr из Boost обладает расширенными возможностями:
- объект может иметь несколько владельцев;
- можно указать дополнительный класс, отвечающий за уничтожение объекта.
#include <boost/shared_ptr.hpp>
#include <iostream>
using namespace boost;
using namespace std;
class A {
shared_ptr<int> ptr;
public:
A(shared_ptr<int> pptr) : ptr(pptr) {}
void setValue(int n) {*ptr=n;}
};
class B {
shared_ptr<int> ptr;
public:
B(shared_ptr<int> pptr) : ptr(pptr) {}
int getValue() const {return *ptr; }
};
int main() {
shared_ptr<int> ptr(new int(45));
A a(ptr);
B b(ptr);
cout<<"b.getValue()="<<b.getValue()<<endl;
a.setValue(50);
cout<<"now b.getValue()="<<b.getValue()<<endl;
}
new/delete и классы
Оператор new можно перегрузить для новых классов, а оператор delete для классов автоматически вызывает деструктор.
альтернативы new/delete
Как альтернативой можно воспользоваться С функциями (объявлены в stdlib.h) как malloc и free. Эти функции нельзя смешивать с операторами динамической памяти, то есть нельзя выделить память оператором new и освободить ее функцией free или наоборот.
Также не следует забывать системные возможности управления памятью, например в Windows API есть функции для управления кучей (HeapCreate, HeapAlloc, HeapFree,...) и виртуальной памятью (VirtualAlloc, VirtualFree,...).