int j = 10;//память выделится в стеке (stack) int* i = new int(10);//память выделится в куче (heap)
К примеру, для переменных цикла не стоит выделять память в куче: потребуется дополнительное время на выделение памяти при создании переменной, разыменование указателя при итеративном обращении к значению переменной и освобождение памяти после окончания работы цикла.
Когда необходимо использовать указатель на объект:
Умный указатель – структура, которая управляет указателем. В конструкторе ей передается указатель, а в деструкторе она его освобождает. В таком случае пользователю не приходится заботиться об утечке памяти.
Picture* p = new Picture();//обычный указатель на объект типа Picture Picture_ptr pp(new Picture());//умный указатель
Picture* a = new Picture(); Auto_ptr b = a; //после этого а перестает указывать на объект
void Picture::release(){ --m_refs; if(m_refs == 0){ delete this; } }Использование Release() корректно, если после вызова delete this; не происходит обращения к полям удаляемого объекта.
Intrusive_Picture(Picture* p){ if(p){ p->addref(); } //... } void Picture::addref(){ ++m_refs; }
Различия с Shared_ptr:
Scoped_ptr | Shared_ptr | Auto_ptr | Intrusive_ptr | Linked_ptr |
|
|
|
|
|
Возможные проблемы в использовании умных указателей:
Предоставляет возможность расширения функциональности класса. Понятие наследования и производного класса предназначены для выражения иерархических отношений, т.е. отражения общности классов.
struct OutputFile{ //… void write(char const *); }; struct MyOutputFile{ //… void write(HTML const &); };
struct MyOutputFile : public OutputFile { //… };
При наследовании классов модификатор public указывать обязательно, для структур - нет. В случае, когда MyOutputFile унаследован от OutputFile метод write(HTML const &) полностью перекроет метод write(char const *) даже учитывая, что эти методы различаются типами передаваемых аргументов. Если в MyOutputFile добавить using OutputFile::write(), тогда метод write (HTML const &) не перекроет метод базового класса и у объектов MyOutputFile можно будет вызывать write(char const*).
При наследовании конструктор и деструктор не наследуются.
MyOutputFile(char const *filename) : OutputFile(filename){ //… }
Если в MyOutputFile определить метод с таким же именем и сигнатурой, как и в базовом, то обратиться к методу базового объекта можно через имя базового класса OutputFile::write(); Так же можно вызвать метод базового класса у объекта класса-наследника.
MyOutputFile mf(filename); mf.OutputFile::write(“text”);
В памяти, выделенной под объект типа MyOutputFile, сначала расположены данные, унаследованные от базового класса, далее следуют данные относящиеся только к типу MyOutputFile.
Наследование может быть многоуровневым, то есть класс OutputFile может быть унаследован от какого-либо другого типа. При создании объекта класса-наследника сначала вызываются конструкторы всех базовых классов в порядке иерархии, начиная с самого верхнего. Деструкторы вызываются в обратном порядке.
Другой пример использования наследования:
В классификации объектов отношение «является» приводит к неявному приведению.
Наследование:
MyOutputFile f;
OutputFile & of = f;
of.write(“”);// вызовется метод родителя
Student s;
Person p = s;
В переменную p скопируются только поля, унаследованные от Person. Данный эффект называют срезкой.