Чтение онлайн

ЖАНРЫ

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

Статическая память (static storage). Переменные, объявленные в глобальной области видимости и в области видимости пространства имен, хранятся в статической памяти, как и переменные, явно объявленные с помощью ключевого слова

static
в функциях и классах. Редактор связей выделяет статическую память до запуска программы.

Свободная память (куча) (free store (heap)). Объекты, созданные с помощью оператора

new
, размещаются в свободной памяти.

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

vector<int> vg(10); // создается один раз
при старте программы

// ("до функции main")

vector<int>* f(int x)

{

static vector<int> vs(x); // создается только при первом

// вызове f

vector<int> vf(x+x); // создается при каждом вызове f

for (int i=1; i<10; ++i) {

vector<int> vl(i); // создается на каждой итерации

// ...

} // переменная v1 уничтожается здесь (на каждой итерации)

return new vector<int>(vf); // создается в свободной памяти

// как копия переменной vf

} // переменная vf уничтожается здесь

void ff

{

vector<int>* p = f(10); // получает вектор от функции f

// .. .

delete p; // удаляет вектор, полученный от

// функции f

}

Переменные

vg
и
vs
, размещенные в статической памяти, уничтожаются по завершении программы (после функции
main
), при условии, что они были созданы.

Память для членов класса отдельно не выделяется. Когда вы размещаете объект где-то, то нестатические члены размещаются там же (в том же классе памяти, что и сам объект, которому они принадлежат).

Код хранится отдельно от данных. Например, функция-член не хранится в каждом объекте своего класса; одна ее копия хранится вместе с остальной частью кода программы.

См. также разделы 14.3 и 17.4.

A.4.3. Время жизни

Перед тем как объект будет (легально) использован, он должен быть проинициализирован. Эту инициализацию можно осуществить явно, с помощью инициализатора, или неявно, используя конструктор или правило инициализации объектов встроенных типов по умолчанию. Время жизни объекта заканчивается в точке, определенной его областью видимости и классом памяти (например, см. разделы 17.4 и Б.4.2).

Локальные (автоматические) объекты создаются, когда поток выполнения достигает их определения, и уничтожаются при выходе из области видимости.

Временные объекты создаются конкретным подвыражением и уничтожаются по завершении полного выражения. Полное выражение — это выражение, которое не является подвыражением другого выражения.

Объекты в пространстве имен и статические члены классов создаются в начале программы (до функции

main
) и уничтожаются в конце программы (после функции
main
”).

Локальные статические объекты создаются, когда поток выполнения достигает их определения и (если они были созданы) уничтожаются в конце программы.

Объекты в свободной

памяти создаются оператором
new
и (необязательно) уничтожаются с помощью оператора
delete
.

Временная переменная, связанная с локальной ссылкой, существует столько же, сколько и сама ссылка. Рассмотрим пример.

const char* string_tbl[] = { "Mozart", "Grieg", "Haydn", "Chopin" };

const char* f(int i) { return string_tbl[i]; }

void g(string s){}

void h

{

const string& r = f(0); // связываем временную строку

// с ссылкой r

g(f(1)); // создаем временную строку

// и передаем ее

string s = f(2); // инициализируем s временной строкой

cout << "f(3): " << f(3) // создаем временную строку

// и передаем ее

<< "s: " << s

<< "r: " << r << '\n';

}

Результат выглядит следующим образом:

f(3): Chopin s: Haydn r: Mozart

Временные строки, сгенерированные при вызовах

f(1)
,
f(2)
и
f(3)
, уничтожаются в конце выражения, в котором они были созданы. Однако временная строка, сгенерированная при вызове
f(0)
, связана с переменной
r
и “живет” до конца функции
h
.

A.5. Выражения

В этом разделе описываются операторы языка C++. Мы используем обозначения, которые считаем мнемоническими, например:

m
— для имени члена;
T
— для имени типа;
p
— для выражения, создающего указатель;
x
— для выражения;
v
для выражения
lvalue
;
lst
— для списка аргументов. Типы результатов арифметических операций определяются обычными арифметическими преобразованиями (раздел A.5.2.2). Описания, приведенные в этом разделе, касаются только встроенных операторов, а не операторов, которые программист может определить самостоятельно, хотя, определяя свои собственные операторы, следует придерживаться семантических правил, установленных для встроенных операторов (см. раздел 9.6).

Обратите внимание на то, что члены могут быть сами вложенными, поэтому можем получить такие выражения, как

N::C::m
(см. также раздел 8.7).

Оператор

typeid
и его применения не описаны в этой книге; его детали можно найти в более сложных учебниках. Обратите внимание на то, что операторы приведения не модифицируют свой аргумент. Вместо этого они создают результат своего типа, который каким-то образом соответствует значению аргумента (раздел A.5.7).

Поделиться с друзьями: