Мегаобучалка Главная | О нас | Обратная связь


Не пишите код, который зависит от порядка вычислений аргументов функции



2016-01-26 434 Обсуждений (0)
Не пишите код, который зависит от порядка вычислений аргументов функции 0.00 из 5.00 0 оценок




 

 

Резюме

 

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

 

Обсуждение

 

На начальных этапах развития языка C регистры процессора были драгоценным ресурсом и компиляторы решали трудные задачи эффективного их использования в сложных выражениях высокоуровневых языков. Для того чтобы позволить компилятору генерировать более быстрый код, создатели C дали распределителю регистров дополнительную степень свободы. При вызове функции порядок вычисления ее аргументов оставался неопределенным. Эта аргументация, вероятно, существенно менее важна в настоящее время, но главное, что порядок вычисления аргументов функций в C++ не определен и варьируется от компилятора к компилятору (см. также рекомендацию 30).

В связи с этим необдуманные действия программиста могут привести к большим неприятностям. Рассмотрим следующий код:

void Transmogrify(int, int);

 

int count = 5;

Transmogrify(++count, ++count); // Порядок вычислений

// неизвестен

Все, что мы можем сказать определенного, — это то, что при входе в тело функции Transmogrify значение переменной count будет равно 7 — но мы не можем сказать, какой аргумент будет равен 6, а какой — 7. Эта неопределенность остается и в гораздо менее очевидных случаях, таких как функции, модифицирующие свои аргументы (или некоторое глобальное состояние) в качестве побочного действия:

int Bump(int& x) { return ++x; }

Transmogrify(Bump(count), Bump(count)); // Результат

// неизвестен

Согласно рекомендации 10, следует в первую очередь избегать глобальных и совместно используемых переменных. Но даже если вы благополучно устраните их, некоторый другой код может этого не сделать. Например, некоторые стандартные функции имеют побочные действия (например, strtok, а также разные перегруженные операторы operator<<, принимающие в качестве аргумента ostream).

Рецепт очень прост — использовать именованные объекты для того, чтобы обеспечить порядок вычислений (см. рекомендацию 13):

int bumped = ++count;

Transmogrify(bumped, ++count); // все в порядке

 

Ссылки

 

[Alexandrescu00c] • [Cline99] §31.03-05 • [Dewhurst03] §14-15 • [Meyers96] §9-10 • [Stroustrup00] §6.2.2, §14.4.1 • [Sutter00] §16 • [Sutter02] §20-21

 

 

Проектирование классов и наследование

 

Наиболее важный аспект разработки программного обеспечения — ясно понимать, что именно вы пытаетесь построить.

— Бьярн Страуструп (Bjarne Stroustrup)

 

Какого вида классы предпочитает разрабатывать и строить ваша команда? Почему?

Интересно, что большинство рекомендаций данного раздела вызваны в первую очередь вопросами зависимостей. Например, наследование — вторая по силе взаимосвязь, которую можно выразить в C++ (первая — отношение дружбы), и такую сильную связь надо использовать очень осторожно и продуманно.

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

В следующем разделе мы обратимся к Большой Четверке специальных функций — конструктору по умолчанию, копирующему конструктору, копирующему присваиванию и деструктору.

В этом разделе мы считаем самой важной рекомендацию 33 — "Предпочитайте минимальные классы монолитным".

 

Ясно представляйте, какой вид класса вы создаете

 

 

Резюме

 

Существует большое количество различных видов классов, и следует знать, какой именно класс вы создаете.

 

Обсуждение

 

Различные виды классов служат для различных целей и, таким образом, следуют различным правилам.

Классы-значения (например, std::pair, std::vector) моделируют встроенные типы. Эти классы обладают следующими свойствами.

• Имеют открытые деструктор, копирующий конструктор и присваивание с семантикой значения.

• Не имеют виртуальных функций (включая деструктор).

• Предназначены для использования в качестве конкретных классов, но не в качестве базовых (см. рекомендацию 35).

• Обычно размещаются в стеке или являются непосредственными членами другого класса.

Базовые классы представляют собой строительные блоки иерархии классов. Базовый класс обладает следующими свойствами.

• Имеет деструктор, который является либо открытым и виртуальным, либо защищенным и невиртуальным (см. рекомендацию 50), а также копирующий конструктор и оператор присваивания, не являющиеся открытыми (см. рекомендацию 53).

• Определяет интерфейс посредством виртуальных функций.

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

Говоря упрощенно, классы свойств представляют собой шаблоны, которые несут информацию о типах. Класс свойств обладает следующими характеристиками.

• Содержит только операторы typedef и статические функции. Класс не имеет модифицируемого состояния или виртуальных функций.

• Обычно объекты данного класса не создаются (конструкторы могут быть заблокированы).

Классы стратегий (обычно шаблоны) являются фрагментами сменного поведения. Классы стратегий обладают следующими свойствами.

• Могут иметь состояния и виртуальные функции, но могут и не иметь их.

• Обычно объекты данного класса не создаются, и он выступает в качестве базового класса или члена другого класса.

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

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

• Имеют виртуальные функции и часто реализуют клонирование (см. рекомендацию 54).

• Предпочтительно делать их производными от std::exception.

Вспомогательные классы обычно поддерживают отдельные идиомы (например, RAII — см. рекомендацию 13). Важно, чтобы их корректное использование не было сопряжено с какими-либо трудностями и наоборот — чтобы применять их некорректно было очень трудно (например, см. рекомендацию 53).

 

Ссылки

 

[Abrahams01b] • [Alexandrescu00a] • [Alexandrescu00b] • [Alexandrescu01] §3 • [Meyers96] §13 • [Stroustrup00] §8.3.2, §10.3, §14.4.6, §25.1 • [Vandevoorde03] §15

 



2016-01-26 434 Обсуждений (0)
Не пишите код, который зависит от порядка вычислений аргументов функции 0.00 из 5.00 0 оценок









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

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

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



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (434)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.007 сек.)