KnigkinDom.org» » »📕 Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

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

1 ... 179 180 181 182 183 184 185 186 187 ... 337
Перейти на страницу:

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
в vector нет

vector v0(10);  // OK

void f(const vector&);

f(10);          // ошибка: преобразования int в vector нет

f(vector(10)); // OK

Для того чтобы избежать неожиданных преобразований, мы — и стандарт языка — потребовали, чтобы конструктор класса vector с одним аргументом имел спецификатор explicit. Очень жаль, что все конструкторы не имеют спецификатора explicit по умолчанию; если сомневаетесь, объявляйте конструктор, который может быть вызван с одним аргументом, используя ключевое слово explicit. 

118.3.2. Отладка конструкторов и деструкторов

 

 Конструкторы и деструкторы вызываются в точно определенных и предсказуемых местах программы. Однако мы не всегда пишем явные вызовы, например vector(2); иногда мы пишем объявление объекта класса vector, передаем его как аргумент функции по значению или создаем в свободной памяти с помощью оператора new. Это может вызвать замешательство у людей, думающих в терминах синтаксиса. Не существует синтаксической конструкции, которая осуществляла бы диспетчеризацию вызовов конструкторов. О конструкторах и деструкторах проще думать следующим образом.

• Когда создается объект класса X, вызывается один из его конструкторов.

• Когда уничтожается объект типа X, вызывается его деструктор.

Деструктор вызывается всегда, когда уничтожается объект класса; это происходит, когда объект выходит из области видимости, программа прекращает работу или к указателю на объект применяется оператор delete. Подходящий конструктор вызывается каждый раз, когда создается объект класса; это происходит при инициализации переменной, при создании объекта с помощью оператора new (за исключением встроенных типов), а также при копировании объекта.

Что же при этом происходит? Для того чтобы понять это, добавим в конструкторы, операторы копирующего присваивания и деструкторы операторы вывода. Рассмотрим пример.

struct X { // простой тестовый класс

  int val;

  void out(const string& s)

    { cerr << this << "–>" << s << ": " << val << "n"; }

  X(){ out("X()"); val=0; }      // конструктор по умолчанию

  X(int v) { out( "X(int)"); val=v; }

  X(const X& x){ out("X(X&) "); val=x.val; } // копирующий

                                             // конструктор

  X& operator=(const X& a)       // копирующее присваивание

    { out("X::operator=()"); val=a.val; return *this; }

  ~X() { out("~X()"); }          // деструктор

};

Проследим, что происходит при выполнении операций над объектом класса X. Рассмотрим пример.

X glob(2);   // глобальная переменная

X copy(X a) { return a; }

X copy2(X a) { X aa = a; return aa; }

X& ref_to(X& a) { return a; }

X* make(int i) { X a(i); return new X(a); }

struct XX { X a; X b; };

int main()

{

  X loc(4);         // локальная переменная

  X loc2 = loc;

  loc = X(5);

  loc2 = copy(loc);

  loc2 = copy2(loc);

  X loc3(6);

  X& r = ref_to(loc);

  delete make(7);

  delete make(8);

  vector<X> v(4);

  XX loc4;

  X* p = new X(9);  // объект класса Х в свободной памяти

  delete p;

  X* pp = new X[5]; // массив объектов класса X

                    // в свободной памяти

  delete[]pp;

}

Попробуйте выполнить эту программу.

ПОПРОБУЙТЕ

Мы имеем в виду следующее: выполните эту программу и убедитесь, что понимаете результаты ее работы. Если понимаете, то вы знаете почти все, что требуется знать о создании и уничтожении объектов.

 

 В зависимости от качества вашего компилятора вы можете заметить пропущенные копии, связанные с вызовами функций copy() и copy2(). Мы (люди) видим, что эти функции ничего не делают; они просто копируют значение из потока ввода в поток вывода без каких-либо изменений. Если компилятор настолько хорош, что заметит это, то сможет удалить эти вызовы конструктора копирования. Иначе говоря, компилятор может предполагать, что конструктор копирования только копирует и ничего больше не делает. Некоторые компиляторы настолько “умны”, что могут исключить фиктивные копии.

Так зачем же возиться с этим “глупым классом X”? Это напоминает упражнения для пальцев, которые выполняют музыканты. После этих упражнений многие вещи, которые обладают намного большим смыслом, становятся понятнее и легче. Кроме того, если у вас возникнут проблемы с конструкторами и деструкторами, рекомендуем вставить в них операторы вывода и посмотреть, как они работают. Для более крупных программ такая отладка становится утомительной, но для них изобретены аналогичные технологии отладки. Например, мы можем выявить, происходит ли утечка памяти, определив, равна ли нулю разность между количеством вызовов конструктора и деструктора. Программисты часто забывают определить копирующие конструкторы и копирующее присваивание для классов, выделяющих память или содержащих указатели на объекты. Это порождает проблемы (которые, впрочем, легко устранить).

Если ваши проблемы слишком велики, чтобы решить их с помощью таких простых средств, освойте профессиональные средства отладки; они называются детекторами утечек (leak detectors). В идеале, разумеется, следует не устранять утечки, а программировать так, чтобы они вообще не возникали. 

18.4. Доступ к элементам вектора

До сих пор (см. раздел 17.6) для доступа к элементам вектора мы использовали функции-члены set() и get(). Но этот способ слишком громоздок и некрасив. Мы хотим использовать обычную индексацию: v[i]. Для этого следует определить функцию-член с именем operator[]. Вот ее первая (наивная) версия.

class vector {

  int sz;         // размер

  double* elem;   // указатель на элементы

public:

  // ...

  double operator[](int n) { return elem[n]; } // возвращаем

                                               // элемент

};

Все выглядит хорошо и просто, но, к сожалению, слишком просто. Разрешив оператору индексирования (operator[]()) возвращать значение, мы разрешили чтение, но не запись элементов.

vector v(10);

int x = v[2]; // хорошо

v[3] = x;     // ошибка: v[3] не может стоять в левой

              // части оператора =

Здесь выражение v[i] интерпретируется как вызов оператора v.operator[](i), который возвращает значение элемента вектора v с номером i. Для такого слишком наивного варианта класса vector значение v[3] является числом с плавающей точкой, а не переменной, содержащей число с плавающей точкой.

ПОПРОБУЙТЕ

Создайте вариант класса vector, скомпилируйте его и

1 ... 179 180 181 182 183 184 185 186 187 ... 337
Перейти на страницу:
Отзывы - 0

Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.


Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.


Партнер

Новые отзывы

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