Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!
Шрифт:
Интервал:
Закладка:

Теперь деструктор может работать правильно. Каждый набор элементов будет корректно удален. Очевидно, что два объекта класса 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. Копирующее присваивание

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 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
Эту ситуацию можно проиллюстрировать так.


Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.
Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.
- 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
- 2. Просьба отказаться от оскорблений, угроз и запугиваний.
- 3. Просьба отказаться от нецензурной лексики.
- 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.
Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.
Оставить комментарий
-
Гость Татьяна24 сентябрь 22:20 Как то не очень... Невеста по ошибке. Я не дам тебе развод - Майя Линн
-
Римма24 сентябрь 21:52 Почему главные героинитпкие идиотки? И сюжет не плохой, и написано хорошо. Но как героиня - так дура дурой.... Хозяйка маленького дома, или Любимая для дракона - Кира Рамис
-
Римма20 сентябрь 12:27 Много ненужных пояснений и отступлений. Весь сюжет теряет свою привлекательность. Героиня иногда так тупит, что читать не... Хозяйка приюта для перевертышей и полукровок - Елена Кутукова