|
Программирование >> Полиморфизм без виртуальных функций в с++
финальной очистки в основную память подгрузится большая часть страниц программы. Такое использование виртуальной памяти нельзя признать разумным, ибо при запуске объемных приложений будет наблюдаться заметная (порядка нескольких секунд) задержка. Для разработчика инстру.ментальных средств тривиальное решение - .модифицировать компоновшик так, чтобы он собирал весь код, выполняе.мый при инициализации, в одном месте. Сложностей не возникает и в случае, когда система ни в каком виде не поддерживает частичную динамическую загрузку программы в основную память. Однако это слабое утешение для программиста на С++, столкнувшегося с такой проблемой [Reiser, 1992]. Мы имеем здесь нарушение основополагаюшего принципа, говорящего, что любая возможность С++ должна быть не только полезной, но и не накладной (см. раздел 4.3). Можно ли решить проблему, добавив какое-то новое средство? На первый взгляд, нет, поскольку ни дизайн языка, ни даже официальные комитеты по стандартизации не могут узаконить эффективность языка. В предложениях, которые мне довелось читать, делаются попытки решить проблему зависи.мости от порядка, которая уже решена приемом, предложенным Джерри, но не касаются возникающего при этом вопроса об эффективности. Подозреваю, что настоящее решение состоит в том, чтобы убедить разработчиков инструментальных средств предотвратить избиение виртуальной памяти (virtual memory bashing), вызванное процедурами динамической инициализации. Для этого нужно лишь вставить необходимые слова в стандарт. 3.11.4.3. Динамическая инициализация встроенных типов В языке С статический объект можно инициализировать лишь слегка расширенным константным выражением, например: double PI = 22/7; /* правильно */ double sqrt2 = sqrt{2);/* в С это ошибка */ Однако в С++ возможны выражения общего вида при инициализации объектов, например: Double s2 = sqrt(2); правильно Стало быть, для встроенных типов обеспечивается меньшая поддержка, чем для классов. Это несоответствие было окончательно исправлено в версии 2.0: double sqrt2 = sqrt(2); правильно в С++ (начиная с версии 2.0) 3.11.5. Предложения объявления в Algol68 есть прекрасная идея о том, что объявление может вводиться в любом месте, а не только в начале блока. В С++ я сделал возможными идиомы только инициализация или единственное присваивание , менее подверженные ошибкам, чем традиционный стиль. Такой подход абсолютно необходим для ссылок и констант, которым нельзя присваивать значения, и более эффективен для типов, инициализация которых по умолчанию - дорогая операция. Например: void f(int i, const char* p) { if {i<=0) error( отрицательный индекс ); const int len = strlen(p); String s(p); . . . Гарантированная инициализация за счет конструкторов - это другая сторона усилий, направленных на уменьшение числа ошибок из-за переменных. 3.115.1 Объявления в циклах for Одна из самых распространенных причин для введения новой переменной в середине блока - объявление переменной цикла. Например: int i; for (i = 0; i<MAX; i + + ) . . . Чтобы не разделять объявление переменной и ее инициализацию, объявление было разрешено переносить в заголовок цикла: for (int i = 0; i<MAX; i + + ) . . . К сожалению, я не стал менять семантику так, чтобы ограничить область действия переменной, введенной таким образом, областью действия предложения for. Основная причина была в том, чтобы избежать специального исключения из правила, гласящего: область действия переменной простирается от точки объявления до конца наименьшего объемлющего блока . Это правило стало предметом многочисленных споров и, в конце концов, было пересмотрено, так чтобы соответствовать правилу для объявлений в условиях (см. раздел 3.11.5.2). Именно имя, введенное инициализатором цикла for, выходит из области действия в конце этого предложения. 3.11.5.2. Объявления в условиях Пользователи, добросовестно старающиеся избежать неинициализированных переменных, сталкиваются с такими примерами: □ переменные, используемые для ввода: int i ; cin i ; □ переменные, используемые в условиях: Ток *ct; if (ct = gettokO) {/*...*/} При проектировании механизма идентификации типов во время исполнения в 1991 г. (см. раздел 14.2.2.1), я обнаружил, что вторую причину появления неинициализированных переменных можно устранить, если разрешить объявления в условиях: if (Ток* ct = gettokO ) { здесь ct находится в области действия а здесь ct уже вышла из области действия Это не просто трюк с целью уменьшить число вводимых символов, а функционирование в точном соответствии с правилами локального объявления переменных. Объединив в одно.м предложении объявление переменной, ее инициализацию и проверку результата инициализации, мы добиваемся компактности, позволяющей устранить ошибку, которая .может возникнуть вследствие использования неинициализированной переменной. Ограничив область действия такой переменной предложением, управляе.мым условие.м, мы также решили проблему случайного повторного использования переменных, которые больше не нужны. На мысль разрешить объявления в выражениях меня натолкнуло изучение языков на базе выражений, прежде всего Algol68. Так, в Algol68 объявление порождало значение, и этот принцип я положил в основу своего дизайна. Позже стало понятно, что память подвела меня: как раз объявления были одной из немногих конструкций в Algol68, которые значений не порождали! Вот что сказал по этому поводу Чарльз Линдсей: Даже в Algol68 есть несколько изъянов, которые говорят о том, что этот язык не полностью непротиворечив . Если бы я проектировал язык с нуля, то пошел бы по пути Algol68 и сделал бы каждое предложение и объявление выражением, и.меющим значение. Возможно, неинициализированные пере.менные были бы полностью запрещены и не разрешалось бы указывать более одного и.мени в одном объявлении. Однако эти идеи, очевидно, неприемлемы для С++. 3.12. Языки С и С++ После появления названия С-и- и написания справочного руководства по языку [Stroustrup, 1984] вопросом, которому придавалось большое значение и вокруг которого завязалась ожесточенная полемика, стала совместимость нового языка с С. Кроме того, в начале 1983 г. подразделение Bell Labs, занимавшееся разработкой и поддержкой UNIX и выпускавшее серию компьютеров AT&T ЗВ, заинтересовалось С-1-1- настолько, что решило выделить ресурсы под разработку инструментальных средств для него. Наличие инструментария было необходимо для того, чтобы С-и- стал языком, который мог использоваться компанией для создания важных проектов. К сожалению, это означало также, что С-и- попадает в поле зрения административных структур, отвечающих за разработку. Сначала руководство потребовало обеспечить стопроцентную совместимость языка с С. Вообще совместимость - это вполне разумно, но практика программирования не так проста. Во-первых, с каким именно С должен быть совместим С-н-? У С было множество диалектов, и, хотя на горизонте вырисовывался ANSI С, до появления стабильного определения должны были пройти годы, причем диалекты все равно до конца не устранялись. Помню, я тогда подсчитал - в шутку, но ведь в каждой шутке есть доля правды, - что может существовать примерно
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |