Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Липпман.doc
Скачиваний:
8
Добавлен:
14.08.2019
Размер:
7.54 Mб
Скачать

5.2. Инструкции объявления

В С++ определение объекта, например

int ival;

рассматривается как инструкция объявления (хотя в данном случае более правильно было бы сказать определения). Ее можно использовать в любом месте программы, где разрешено употреблять инструкции. В следующем примере объявления помечены комментарием //#n, где n – порядковый номер.

#include <fstream>

#include <string>

#include <vector>

int main()

{

string fileName; // #1

cout << "Введите имя файла: ";

cin >> fileName;

if ( fileName.empty() ) {

// странный случай

cerr << "Пустое имя файла. Завершение работы.\n";

return -1;

}

ifstream inFile( fileName.c_str() ); // #2

if ( ! inFile ) {

cerr << "Невозможно открыть файл.\n";

return -2;

}

string inBuf; // #3

vector< string > text; // #4

while ( inFile >> inBuf ) {

for ( int ix = 0; ix < inBuf .size(); ++ix ) // #5

// можно обойтись без ch,

// но мы использовали его для иллюстрации

if (( char ch = inBuf[ix] )=='.'){ // #6

ch = '_';

inBuf[ix] = ch;

}

text.push_back( inBuf );

}

if ( text.empty() )

return 0;

// одна инструкция объявления,

// определяющая сразу два объекта

vector<string>::iterator iter = text.begin(), // #7

iend = text.end();

while ( iter != -iend ) {

cout << *iter << '\n';

++iter;

}

return 0;


}

Программа содержит семь инструкций объявления и восемь определений объектов. Объявления действуют локально; переменная объявляется непосредственно перед первым использованием объекта.

В 70-е годы философия программирования уделяла особое внимание тому, чтобы определения всех объектов находились в начале программы или блока, перед исполняемыми инструкциями. (В С, например, определение переменной не является инструкцией и обязано располагаться в начале блока.) В некотором смысле это была реакция на идиому использования переменных без предварительного объявления, чреватую ошибками. Такую идиому поддерживал, например, FORTRAN.

Поскольку в С++ объявление является обычной инструкцией, ему разрешено появляться в любом месте программы, где допустимо употребление инструкции, что дает возможность использовать локальные объявления.

Необходимо ли это? Для встроенных типов данных применение локальных объявлений является скорее вопросом вкуса. Язык их поощряет , разрешая объявлять переменные внутри условных частей инструкций if, if-else, switch, while, for. Те программисты, которые любят этот стиль, верят, что таким образом делают свои программы более понятными.

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

  • конструкторы всех объектов вызываются перед исполнением первой инструкции блока. Применение локальных объявлений позволяет “размазать” расходы на инициализацию по всему блоку;

  • что более важно, блок или функция могут завершиться до того, как будут действительно использованы все объявленные в начале объекты. Скажем, наша программа из предыдущего примера имеет два аварийных выхода: при вводе пользователем пустого имени файла и при невозможности открыть файл с заданным именем. При этом последующие инструкции функции уже не выполняются. Если бы объекты inBuf и next были объявлены в начале блока, конструкторы и деструкторы этих объектов в случае ненормального завершения функции вызывались бы совершенно напрасно.

Инструкция объявления может состоять из одного или более определений. Например, в нашей программе мы определяем два итератора вектора в одной инструкции:

// одна инструкция объявления,

// определяющая сразу два объекта

vector<string>::iterator iter = text.begin(),


lend = text.end();

Эквивалентная пара, определяющая по одному объекту, выглядит так:

vector<string>::iterator iter = text.begin();


vector<string>::iterator lend = text.end();

Хотя определение одного или нескольких объектов в одном предложении является скорее вопросом вкуса, в некоторых случаях – например, при одновременном определении объектов, указателей и ссылок – это может спровоцировать появление ошибок. Скажем, в следующей инструкции не совсем ясно, действительно ли программист хотел определить указатель и объект или просто забыл поставить звездочку перед вторым идентификатором (используемые имена переменных наводят на второе предположение):

// то ли хотел определить программист?


string *ptrl, ptr2;

Эквивалентная пара инструкций не позволит допустить такую ошибку:

string *ptr1;


string *ptr2;

В наших примерах мы обычно группируем определения объектов в инструкции по сходству употребления. Например, в следующей паре

int aCnt=0, eCnt=0, iCnt=0, oCnt=0, uCnt=0;


int charCnt=0, wordCnt=0;

первая инструкция объявляет пять очень похожих по назначению объектов – счетчиков пяти гласных латинского алфавита. Счетчики для подсчета символов и слов определяются во второй инструкции. Хотя такой подход нам кажется естественным и удобным, нет никаких причин считать его хоть чем-то лучше других.

Упражнение 5.1

Представьте себе, что вы являетесь руководителем программного проекта и хотите, чтобы применение инструкций объявления было унифицировано. Сформулируйте правила использования объявлений объектов для вашего проекта.

Упражнение 5.2

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