Конструирование "Достаточно длинное имя"

    Деструкция "Достаточно длинное имя"

    Деструкция "Уже освобождённая память"

    Возврат из fn( )

    Press any key to continue...

В этом примере конструктор для Person выделяет память из кучи для хранения в ней имени произвольной длины, что невозможно при использовании массивов. Деструктор возвращает эту память в кучу. Основная программа вызывает функцию fn( ), которая создаёт объект p1, описывающий человека, после чего создаётся копия этого объекта — р2. Оба объекта автоматически уничтожаются при выходе из функции fn( ).

После запуска этой программы вы получите сообщение только от одного конструктора. Это неудивительно, поскольку копия р2 создаётся с помощью предоставляемого С++ конструктора копирования по умолчанию, а он не выводит никаких сообщений. Однако, после того как p1 и р2 выходят из области видимости, вы не получите двух сообщений о ликвидации объектов, как можно было ожидать. Первый конструктор выводит ожидаемое сообщение о деструкции объекта, но второй деструктор сообщает, что память уже была освобождена.

«Если бы мы действительно освобождали память в программе, то программа после попытки освободить уже освобождённую память оказалась бы в нестабильном состоянии и могла аварийно завершиться.»

[Атас!]

Конструктор вызывается один раз и выделяет блок памяти из кучи для хранения в нём имени человека. Копирующий конструктор, создаваемый С++, просто копирует этот адрес в новый объект, без выделения нового блока памяти.

Когда объекты ликвидируются, деструктор для р2 первым получает доступ к этому блоку памяти. Этот деструктор стирает имя и освобождает блок памяти. К тому времени как деструктор p1 получает доступ к этому блоку, память уже очищена, а имя стёрто. Теперь понятно, откуда взялось сообщение об ошибке. Суть проблемы проиллюстрирована на рис. 18.1. Объект p1 копируется в новый объект р2, но не копируются используемые им ресурсы. Таким образом, р1 и р2 указывают на один и тот же ресурс ( в данном случае это блок памяти ). Такое явление называется "мелким" ( shallow ) копированием, поскольку при этом копируются только члены класса как таковые.

«Решение этой проблемы визуально показано на рис. 18.2. В данном случае нужен такой копирующий конструктор, который будет выделять ресурсы для нового объекта. Давайте добавим такой конструктор к классу и посмотрим, как он работает ( здесь приведён только фрагмент программы, полностью находящейся на прилагаемом компакт-диске ).»

[Диск]

    class Person

    {

      public :

        Person( char *pN )

        {

            cout << "Конструирование " << pN << endl ;

            pName = new char[ strlen( pN ) + 1 ] ;

            if ( pName != 0 )

            {

                strcpy( pName , pN ) ;

            }

        }

_________________

219 стр. Глава 18. Копирующий конструктор

        /* Копирующий конструктор выделяет новый блок памяти из кучи */

        Person( Person& p )

        {

            cout << "Копирование " << p.pName

                   << " в собственный блок" << endl ;

            pName = new char[ strlen( p.pName ) + 1 ] ;

            if ( pName != 0 )

            {

                strcpy( pName , p.pName ) ;

            }

        }

        ~Person( )

        {

            cout << "Деструкция " << pName << endl ;

            strcpy( pName , "Уже освобождённая память" ) ;

            /* delete pName ; */

        }

      protected :

        char *pName ;

    } ;

Рис. 18.1. Мелкое копирование объекта p1 в р2

Здесь копирующий конструктор выделяет новый блок памяти для имени, а затем копирует содержимое блока памяти исходного объекта в этот новый блок ( рис. 18.2 ). Такое копирование называется "глубоким" ( deep ), поскольку копирует не только элементы, но и занятые ими ресурсы ( конечно, аналогия, как говорится, притянута за уши, но ничего не поделаешь — не я придумал эти термины ).

Запуск программы с новым копирующим конструктором приведёт к выводу на экран следующих строк:

    Вызов fn( )

    Конструирование Достаточно_длинное_имя

Перейти на страницу:

Все книги серии Для чайников

Похожие книги