Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:
image l:href="#"/>

Если бы компилятор пропустил такой код, то мы могли бы записать число

12345
в ячейку памяти, начинающуюся с адреса
&ch3
. Это изменило бы содержание окрестной памяти, т.е. значения переменных
ch2
и
ch4
. В худшем (и самом реальном) случае мы бы перезаписали часть самой переменной
pi
! В этом случае следующее присваивание
*pi=67890
привело бы к размещению числа
67890
в совершенно другой области памяти. Очень хорошо, что такое присваивание запрещено, но таких механизмов защиты на низком уровне программирования очень мало.

В редких ситуациях, когда нам требуется преобразовать переменную типа

int
в указатель или конвертировать один тип показателя в другой, можно использовать оператор
reinterpret_cast
(подробнее об этом — в разделе 17.8).

Итак, мы очень близки к аппаратному обеспечению. Для программиста это не очень удобно. В нашем распоряжении лишь несколько примитивных операций и почти нет библиотечной поддержки. Однако нам необходимо знать, как реализованы высокоуровневые средства, такие как класс

vector
. Мы должны знать, как написать код на низком уровне, поскольку не всякий код может быть высокоуровневым (см. главу 25). Кроме того, для того чтобы оценить удобство и относительную надежность высокоуровневого программирования, необходимо почувствовать сложность низкоуровневого программирования. Наша цель — всегда работать на самом высоком уровне абстракции, который допускает поставленная задача и сформулированные ограничения. В этой главе, а также в главах 18–19 мы покажем, как вернуться на более комфортабельный уровень абстракции, реализовав класс
vector
.

17.3.1. Оператор sizeof

Итак, сколько памяти требуется для хранения типа
int
? А указателя? Ответы на эти вопросы дает оператор
sizeof
.

cout << "размер типа char" << sizeof(char) << ' '

<< sizeof ('a') << '\n';

cout << "размер типа int" << sizeof(int) << ' '

<< sizeof (2+2) << '\n';

int* p = 0;

cout << "размер типа int*" << sizeof(int*) << ' '

<< sizeof (p) << '\n';

Как видим, можно применить оператор

sizeof
как к имени типа, так и к выражению; для типа оператор
sizeof
возвращает размер объекта данного типа, а для выражения — размер типа его результата. Результатом оператора
sizeof
является положительное целое число, а единицей измерения объема памяти является значение
sizeof(char)
, которое по определению равно
1
. Как правило, тип
char
занимает один байт, поэтому оператор
sizeof
возвращает количество байтов.

ПОПРОБУЙТЕ

Выполните код, приведенный выше, и посмотрите на результаты. Затем расширьте этот пример для определения размера типов

bool
,
double
и некоторых других.

Размер одного и того же типа в разных реализациях языка С++ не обязательно совпадает. В настоящее время выражение

sizeof(int)
в настольных компьютерах и ноутбуках обычно равно четырем. Поскольку в байте содержится 8 бит, это значит, что тип
int
занимает 32 бита. Однако в процессорах встроенных систем тип
int
занимает 16 бит, а в высокопроизводительных архитектурах размер типа
int
обычно равен 64 битам.

Сколько памяти занимает объект класса vector? Попробуем выяснить.

vector<int> v(1000);

cout << "Размер объекта типа vector<int>(1000) = "

<< sizeof (v) << '\n';

Результат может выглядеть так:

Размер объекта типа vector<int>(1000) = 20

Причины этого факта станут очевидными по мере чтения этой и следующей глав (а также раздела 19.2.1), но уже сейчас ясно, что оператор

sizeof
не просто пересчитывает элементы.

17.4. Свободная память и указатели

Рассмотрим реализацию класса
vector
, приведенную в конце раздела 17.2. Где класс
vector
находит место для хранения своих элементов? Как установить указатель
elem
так, чтобы он ссылался на них? Когда начинается выполнение программы, написанной на языке С++, компилятор резервирует память для ее кода (иногда эту память называют кодовой (code storage), или текстовой (text storage)) и глобальных переменных (эту память называют статической (static storage)). Кроме того, он выделяет память, которая будет использоваться при вызове функций для хранения их аргументов и локальных переменных (эта память называется стековой (stack storage), или автоматической (automatic storage)). Остальная память компьютера может использоваться для других целей; она называется свободной (free). Это распределение памяти можно проиллюстрировать следующим образом.

Язык С++ делает эту свободную память (которую также называют кучей (heap)) доступной с помощью оператора

new
. Рассмотрим пример.

double* p = new double[4]; // размещаем 4 числа double в свободной

// памяти

Указанная выше инструкция просит систему выполнения программы разместить четыре числа типа

double
в свободной памяти и вернуть указатель на первое из них. Этот указатель используется для инициализации переменной
p
. Схематически это выглядит следующим образом.

  • Читать дальше
  • 1
  • ...
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: