- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
Мы должны гарантировать, что выхода за пределы допустимого диапазона не будет. Одна из причин, по которым мы используем класс vector, а не выделяем память непосредственно с помощью оператора new, заключается в том, что класс vector знает свой размер и поэтому выход за пределы допустимого диапазона можно предотвратить.
Предотвратить выход за пределы допустимого диапазона сложно по многим причинам. Одна из них заключается в том, что мы можем присваивать один указатель double* другому указателю double* независимо от количества элементов, на которые они ссылаются. Указатель действительно не знает, на сколько элементов он ссылается. Рассмотрим пример.
double* p = new double; // разместить переменную типа double
double* q = new double[1000]; // разместить тысячи переменных double
q[700] = 7.7; // отлично
q = p; // пусть указатель q ссылается на то же, что и p
double d = q[700]; // выход за пределы допустимого диапазона!
Здесь всего три строки кода, в которых выражение q[700] ссылается на две разные ячейки памяти, причем во втором случае происходит опасный выход за пределы допустимого диапазона.
Теперь мы надеемся, что вы спросите: “А почему указатель не может помнить размер памяти?” Очевидно, что можно было бы разработать указатель, который помнил бы, на какое количество элементов он ссылается, — в классе vector это сделано почти так. А если вы прочитаете книги, посвященные языку С++, и просмотрите его библиотеки, то обнаружите множество “интеллектуальных указателей”, компенсирующих этот недостаток встроенных низкоуровневых указателей. Однако в некоторых ситуациях нам нужен низкоуровневый доступ и понимание механизма адресации объектов, а машина не знает, что она адресует. Кроме того, знание механизма работы указателей важно для понимания огромного количества уже написанных программ.
17.4.4. Инициализация
Как всегда, мы хотели бы, чтобы объект уже имел какое-то значение, прежде чем мы приступим к его использованию; иначе говоря, мы хотели бы, чтобы указатели и объекты, на которые они ссылаются, были инициализированы. Рассмотрим пример.
double* p0; // объявление без инициализации:
// возможны проблемы
double* p1 = new double; // выделение памяти для переменной
// типа double
// без инициализации
double* p2 = new double(5.5); // инициализируем переменную типа double
// числом 5.5
double* p3 = new double[5]; // выделение памяти для массива
// из пяти чисел
// типа double без инициализации
Очевидно, что объявление указателя p0 без инициализации может вызвать проблемы. Рассмотрим пример.
*p0 = 7.0;
Эта инструкция записывает число 7.0 в некую ячейку памяти. Мы не знаем, в какой части памяти расположена эта ячейка. Это может быть безопасно, но рассчитывать на это нельзя. Рано или поздно мы получим тот же результат, что и при выходе за пределы допустимого диапазона: программа завершит работу аварийно или выдаст неправильные результаты. Огромное количество серьезных проблем в программах, написанных в старом стиле языка С, вызвано использованием неинициализированных указателей и выходом за пределы допустимого диапазона. Мы должны делать все, чтобы избежать таких проблем, частично потому, что наша цель — профессионализм, а частично потому, что мы не хотим терять время в поисках ошибок такого рода.
Выявление и устранение таких ошибок — ужасно нудное и неприятное дело. Намного приятнее и продуктивнее предотвратить такие ошибки, чем вылавливать их.
Память, выделенная оператором new встроенных типов, не инициализируется. Если хотите инициализировать указатель, задайте конкретное значение, как это было сделано при объявлении указателя p2: *p2 равно 5.5. Обратите внимание на круглые скобки, (), используемые при инициализации. Не перепутайте их с квадратными скобками, [], которые используются для индикации массивов.
В языке С++ нет средства для инициализации массивов объектов встроенных типов, память для которых выделена оператором new. Для массивов работу придется проделать самостоятельно. Рассмотрим пример.
double* p4 = new double[5];
for (int i = 0; i<5; ++i) p4[i] = i;
Теперь указатель p4 ссылается на объекты типа double, содержащие числа 0.0, 1.0, 2.0, 3.0 и 4.0.
Как обычно, мы должны избегать неинициализированных объектов и следить за тем, чтобы они получили значения до того, как будут использованы. Компиляторы часто имеют режим отладки, в котором они по умолчанию инициализируют все переменные предсказуемой величиной (обычно нулем). Это значит, что, когда вы отключаете режим отладки, чтобы отправить программу заказчику, запускаете оптимизатор или просто компилируете программу на другой машине, программа, содержащая неинициализированные переменные, может внезапно перестать работать правильно. Не используйте неинициализированные переменные. Если класс X имеет конструктор по умолчанию, то получим следующее:
X* px1 = new X; // один объект класса Х, инициализированный
// по умолчанию
X* px2 = new X[17]; // 17 объектов класса Х, инициализированных
// по умолчанию
Если класс Y имеет конструктор, но не конструктор по умолчанию, мы должны выполнить явную инициализацию
Y* py1 = new Y; // ошибка: нет конструктора по умолчанию
Y* py2 = new Y[17]; // ошибка: нет конструктора по умолчанию
Y* py3 = new Y(13); // OK: инициализирован адресом объекта Y(13)
17.4.5. Нулевой указатель
Если в вашем распоряжении нет другого указателя, которым можно было бы инициализировать ваш указатель, используйте 0 (нуль).
double* p0 = 0; // нулевой указатель
Указатель, которому присвоен нуль, называют нулевым (null pointer). Корректность указателя (т.е. ссылается ли он на что-либо) часто проверяется с помощью сравнения его с нулем. Рассмотрим пример.
if (p0 != 0) // проверка корректности указателя p0
Этот тест неидеален, поскольку указатель p0 может содержать случайное ненулевое значение или адрес объекта, который был удален с помощью оператора