Слайд 1Тема: Управление памятью
Распределение памяти
Создание и уничтожение объектов
Инкапсуляция управления памятью
Слайд 2Операции new и delete
Объект, размер в памяти которого заранее не
известен, можно создавать в куче (или стеке)
Операция new создает объект
в куче
выделяет память
вызывает конструктор
возвращает указатель на объект (или NULL, если нет свободной памяти)
Объект существует до его явного уничтожения операцией delete
Операция delete уничтожает объект
вызывает деструктор
освобождает память
Слайд 3Распределение памяти: время «Ч»
int i = 34;
int* func( ) {
int*
ptr;
ptr = new int;
*ptr = 75;
return ptr;
}
void func2( ) {
int*
ptr2;
ptr2 = func();
delete ptr2;
}
Слайд 4Использование new и delete
#include “mystring.h”
void main( int argc, char* argv[
] ) {
// Динамическое размещение
// объекта типа String
String* ptr1 ;
ptr1
= new String ;
if( ptr1 == 0 ) exit(1) ;
*ptr1 = “Hello, world”;
(*ptr1 + “\n”).print();
// Динамическое размещение и
// инициализация объекта String
String* ptr2 ;
ptr2 = new String(“Hello, world”) ;
if( ptr2 == 0 ) exit(2) ;
(*ptr2 + “\n”).print();
// Динамическое размещение
// массива объектов типа String
String* ptr3 ;
ptr3 = new String[argc] ;
if( ptr3 == 0 ) exit(1) ;
ptr3[argc-1] = “Hello, world”;
(ptr3[argc-1] + “\n”).print();
// Уничтожение объектов
delete ptr1 ;
delete ptr2 ;
delete [argc] ptr3 ;
// или delete [] ptr3 ;
}
Слайд 5Улучшение класса String
Реализация строки с использованием динамически выделяемой памяти
может быть
скрыта в классе
снимаются ограничения на длину строки
рационально расходуется память
Если принципы
ООП соблюдены, то пользователю не потребуется вносить изменения в программу (но потребуется ее перекомпилировать)
Разработчику потребуется проверить, перепрограммировать и заново отладить методы класса и функции-друзья.
Слайд 6Пересмотренный класс String
class String {
public:
String() ;
String( const char* ) ;
String(
const String& ) ;
~String() ;
operator const char*( ) const;
String& operator=
( const String& );
int length( ) const ;
int read( ); // чтение из stdin
void print( ) const; // вывод в stdout
char& operator[ ] ( int );
const char& operator[ ] ( int ) const;
String substring (int start, int len) const;
friend String operator+ (const String&, const String& );
private:
// text указывает на область динамической памяти,
// всегда завершающуюся терминальным байтом
char* text ;
};
Слайд 7Выделение памяти под объект
(старая реализация)
Слайд 8Выделение памяти под объект
(новая реализация)
String* s_ptr = new String(“Hello”);
*s_ptr
s_ptr->text
s_ptr
адрес
стек
куча
адрес
Hello\0
Слайд 9Создание объектов типа String
String s ;
// или
String* s_ptr ;
s_ptr
= new String ;
перед конструктором
выделена память под указатель text
после
конструктора
text
адрес
text
‘\0’
String::String() {
if( !(text = new char) )
error_msg(“Нет памяти для пустой строки”) ;
*text = ‘\0’ ;
}
Синтаксис
Слайд 10Инициализация объектов типа String
String s = “Hello”;
// или
String* s_ptr
;
s_ptr = new String(“Hello”) ;
выделена память под указатель text
перед конструктором
после конструктора
text
адрес
text
“Hello\0”
String::String( const char* s ) {
if( !(text = new char[strlen(s)+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( text , s) ;
}
Синтаксис
Слайд 11Копирование объектов типа String
String s = t ;
// или
String*
s_ptr ;
s_ptr = new String(t) ;
выделена память под указатель text
перед
конструктором
после конструктора
text
адрес
text
“Hello\0”
String::String( const String& s ) {
if( !(text = new char[s.length()+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( text , s.text ) ;
}
Синтаксис
Слайд 12Уничтожение объектов типа String
String* s_ptr ;
s_ptr = new String ;
//
…………
delete s_ptr ;
// или s уничтожается
// автоматически
перед деструктором
память занята под
указатель text
после деструктора
text
адрес
text
“Hello\0”
String::~String( ) { delete text ; }
Синтаксис
Слайд 13Присваивание объектов типа String
t = s
перед присваиванием
адрес
text
‘\0’
Синтаксис:
t
адрес
text
“Hello\0”
s
после присваивания
адрес
text
t
адрес
text
“Hello\0”
s
“Hello\0”
Слайд 14Операция присваивания объектов типа String
String& String::operator=(const String& s) {
if( this != &s ) { // на случай t=t
delete text ; // освободить старую память
if( !(text = new char[s.length()+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( text , s.text ) ;
}
return *this ;
}
Слайд 15Конкатенация строк
#include “mystring.h”
#include
#include
String operator+(const String& s1 , const
String& s2 ) {
String both ;
delete
both.text ;
if( !(both.text = new char[s1.length()+s2.length()+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( both.text , s1.text ) ;
strcat( both.text , s2.text ) ;
return both ;
}
Слайд 16Использование закрытых методов
inline void String::alloc_and_set(const char* s)
{
if( !(text
= new char[ strlen(s)+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( text , s ) ;
}
В ряде методов класса приходится выполнять одно и то же действие:
выделить участок динамической памяти
заполнить ее символьной строкой
Слайд 17Методы класса String
String::String( ) { alloc_and_set(“”); }
String::String( const String& s
) { alloc_and_set(s.text); }
String::String( const char* s ) { alloc_and_set(
s ); }
String& String::operator=(const String& s) {
if( this != &s ) { // на случай t=t
delete text ; // освободить старую память
alloc_and_set( s.text );
}
return *this ;
}
Слайд 18«Приемчики» эффективности
String operator+(const String& s1 , const String& s2
) {
String both ;
delete
both.text ;
if( !(both.text = new char[s1.length()+s2.length()+1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( both.text , s1.text ) ;
strcat( both.text , s2.text ) ;
return both ;
}
Операция конкатенации неэффективна:
создается переменная both (вызов конструктора)
манипуляции с динамической памятью
возврат результата (вызов конструктора)
Слайд 19Применим закрытый конструктор
String::String(const char* s1, const char* s2) {
if( !(text = new char[ srtlen(s1) + srtlen(s2)
+ 1]) )
error_msg(“Нет памяти для строки \n” ) ;
strcpy( text , s1 ) ;
strcat( text , s2 ) ;
}
inline String operator+(const String& s1 , const String& s2 )
{
return String( s1.text , s2.text ) ;
}
Слайд 20Закрытые методы класса String
class String {
public:
// методы класса
private:
String(const char*
, const char* );
void alloc_and_set(const char* );
// text указывает
на область динамической
// памяти, всегда завершающуюся
// терминальным байтом
char* text ;
};
Слайд 21РЕЗЮМЕ
Классы с динамической памятью
более гибкие и эффективные
более сложные в реализации
Простая
реализация позволяет сосредоточиться на интерфейсе
Изменение реализации не требует изменений программ
пользователей (только перекомпиляция)
Динамические классы требуют нетривиальной реализации
конструкторов
деструктора
операции присваивания
Слайд 22Упражнение
Изменить реализацию класса String так, чтобы длина строки определялась целым
полем len, а сама строка была динамическим массивом символов, но
без терминального байта:
class String {
public:
// те же методы класса
private:
int len;
char* text ;
}
Слайд 23Лабораторная работа
Создать класс intArray, представляющий массив целых чисел. Класс должен
быть объявлен в файле intarray.h. Код методов поместите в любой
файл (или файлы), по своему усмотрению
Спецификация класса intArray
Размер массива Int_array должен задаваться при его создании:
intArray ia(10);
Доступ к элементам массива осуществляется с помощью операции []. (Заметим, что для этого не требуется метод operator=() ).
ia[0] = 100; ia[1] = 10;
Программа прерывается, если задается некорректный индекс:
ia[9] = 17; // все нормально
ia[5000] = 508; // программа прерывается
Слайд 24Массивы типа intArray могут присваиваться; в этом случае, массив intArray
, находящийся слева, получает размер и все элементы массива intArray
, находящегося справа:
intArray ia2(7);
ia2[0] = -1;
ia2 = ia;
Если массив intArray передается функции по значению, функция получает копию этого массива:
test(ia2);
printf("ia2[9] should still be 17: %d\n", ia2[9]);
// тестом является следующий код:
void test(intArray copy) {
printf("copy[9] should be 17: %d\n", copy[9]);
copy[9] = -1;
printf("copy[9] changed to -1: %d\n", copy[9]);
}