- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
Теперь деструктор может работать правильно. Каждый набор элементов будет корректно удален. Очевидно, что два объекта класса vector теперь не зависят друг от друга, и мы можем изменять значения элементов в объекте v, не влияя на содержание объекта v2, и наоборот. Рассмотрим пример.
v.set(1,99); // устанавливаем v[1] равным 99
v2.set(0,88); // устанавливаем v2[0] равным 88
cout << v.get(0) << ' ' << v2.get(1);
Результат равен 0 0.
Вместо инструкции
vector v2 = v;
мы могли бы написать инструкцию
vector v2(v);
Если объекты v (инициализатор) и v2 (инициализируемая переменная) имеют одинаковый тип и в этом типе правильно реализовано копирование, то приведенные выше инструкции эквивалентны, а их выбор зависит от ваших личных предпочтений.
18.2.2. Копирующее присваивание
Копирование векторов может возникать не только при их инициализации, но и при присваивании. Как и при инициализации, по умолчанию копирование производится поэлементно, так что вновь может возникнуть двойное удаление (см. раздел 18.2.1) и утечка памяти. Рассмотрим пример.
void f2(int n)
{
vector v(3); // определяем вектор
v.set(2,2.2);
vector v2(4);
v2 = v; // присваивание: что здесь происходит?
// ...
}
Мы хотели бы, чтобы вектор v2 был копией вектора v (именно так функционирует стандартный класс vector), но поскольку в нашем классе vector смысл копирования не определен, используется присваивание по умолчанию; иначе говоря, присваивание выполняется почленно, и члены sz и elem объекта v2 становятся идентичными элементам sz и elem объекта v соответственно.
Эту ситуацию можно проиллюстрировать следующим образом:
При выходе из функции f2() возникнет такая же катастрофа, как и при выходе из функции f() в разделе 18.2, до того, как мы определили копирующий конструктор: элементы, на которые ссылаются оба вектора, v и v2, будут удалены дважды (с помощью оператора delete[]). Кроме того, возникнет утечка памяти, первоначально выделенной для вектора v2, состоящего из четырех элементов. Мы “забыли” их удалить. Решение этой проблемы в принципе не отличается от решения задачи копирующей инициализации (см. раздел 18.2.1). Определим копирующий оператор присваивания.
class vector {
int sz;
double* elem;
void copy(const vector& arg); // копирует элементы из arg
// в *elem
public:
vector& operator=(const vector&) ; // копирующее присваивание
// ...
};
vector& vector::operator=(const vector& a)
// делает этот вектор копией вектора a
{
double* p = new double[a.sz]; // выделяем новую память
for (int=0; i<asz; ++i)
p[i]=a.elem[i]; // копируем элементы
delete[] elem; // освобождаем память
elem = p; // теперь можно обновить elem
sz = a.sz;
return *this; // возвращаем ссылку
// на текущий объект (см. раздел 17.10)
}
Присваивание немного сложнее, чем создание, поскольку мы должны работать со старыми элементами. Наша основная стратегия состоит в копировании элементов из источника класса vector.
double* p = new double[a.sz]; // выделяем новую память
for(int=0; i<asz; ++i) p[i]=a.elem[i];
Теперь освобождаем старые элементы из целевого объекта класса vector.
delete[] elem; // освобождаем занятую память
В заключение установим указатель elem на новые элементы.
elem = p; // теперь можем изменить указатель elem
sz = a.sz;
Теперь в классе vector утечка памяти устранена, а память освобождается только один раз (delete[]).
Реализуя присваивание, код можно упростить, освобождая память, занятую старыми элементами, до создания копии, но обычно не стоит стирать информацию, если вы не уверены, что ее можно заменить. Кроме того, если вы это сделаете, то при попытке присвоить объект класса vector самому себе могут возникнуть странные вещи.
vector v(10);
v=v; // самоприсваивание
Пожалуйста, убедитесь, что наша реализация функционирует правильно (если не оптимально).
18.2.3. Терминология, связанная с копированием
Копирование встречается в большинстве программ и языков программирования. Основная проблема при этом заключается в том, что именно копируется: указатель (или ссылка) или информация, на которую он ссылается.
• Поверхностное копирование (shallow copy) предусматривает копирование только указателя, поэтому в результате на один и тот же объект могут ссылаться два указателя. Именно этот механизм копирования лежит в основе работы указателей и ссылок.
• Глубокое копирование (deep copy) предусматривает копирование информации, на которую ссылается указатель, так что в результате два указателя ссылаются на разные объекты. На основе этого механизма копирования реализованы классы vector, string и т.д. Если мы хотим реализовать глубокое копирование, то должны реализовать в наших классах конструктор копирования и копирующее присваивание.
Рассмотрим пример поверхностного копирования.
int* p = new int(77);
int* q = p; // копируем указатель p
*p = 88; // изменяем значение переменной int, на которую
// ссылаются указатели p и q
Эту ситуацию можно проиллюстрировать следующим образом.
В противоположность этому мы можем осуществить глубокое копирование.
int* p = new int(77);
int* q = new int(*p); // размещаем новую переменную int,
// затем копируем значение, на которое
// ссылается p
*p = 88; // изменяем значение, на которое ссылается p
Эту ситуацию можно проиллюстрировать так.
Используя эту терминологию, мы можем сказать, что проблема с нашим исходным классом vector заключалась в том, что мы выполняли поверхностное копирование и не копировали элементы, на которые ссылался указатель elem. Наш усовершенствованный класс vector, как и стандартный класс vector, выполняет глубокое копирование, выделяя новую память для элементов и копируя их значения. О типах, предусматривающих поверхностное копирование

