Частые замечания в заданиях по C++ — различия между версиями
Assaron (обсуждение | вклад) |
Sementry (обсуждение | вклад) м (поправил орфографию) |
||
Строка 7: | Строка 7: | ||
* Не надо использовать приведение в C-стиле (type)v или type(v) для встроенных типов (интегральные типы, указатеи, ссылки) — с помощью них можно привести практически все что угодно к чему угодно, следует использовать соответствующие C++ аналоги: static_cast, dynamic_cast, reinterpret_cast и const_cast. | * Не надо использовать приведение в C-стиле (type)v или type(v) для встроенных типов (интегральные типы, указатеи, ссылки) — с помощью них можно привести практически все что угодно к чему угодно, следует использовать соответствующие C++ аналоги: static_cast, dynamic_cast, reinterpret_cast и const_cast. | ||
* Не надо заменять символы их ascii-кодами — следует писать '0', а не 48. | * Не надо заменять символы их ascii-кодами — следует писать '0', а не 48. | ||
− | * Если не предполагается, что переменная должна | + | * Если не предполагается, что переменная должна изменяться, следует объявлять ее константной. Особенно, если это касается сигнатуры функции. |
* Лучше не создавать функций void print_something(something const & s, ostream & o), лучше перегружать operator<<, в котором точно не надо выводить в конце перевод строки. | * Лучше не создавать функций void print_something(something const & s, ostream & o), лучше перегружать operator<<, в котором точно не надо выводить в конце перевод строки. | ||
* Есть замечательные стандартные функции, лежащие в <algorithm>. Не следует изобретать велосипеды и писать свои реализации. Наиболее полезные: reverse, copy, swap, fill, max, min. | * Есть замечательные стандартные функции, лежащие в <algorithm>. Не следует изобретать велосипеды и писать свои реализации. Наиболее полезные: reverse, copy, swap, fill, max, min. | ||
* Есть только один случай, когда название функции может являться существительным — когда название отражает то, что функция возвращает: например, union, gcd, area и т.д. | * Есть только один случай, когда название функции может являться существительным — когда название отражает то, что функция возвращает: например, union, gcd, area и т.д. | ||
* Не надо писать if, for и while в одну строчку. Если внутри for'а ничего не делается, ";" следует перенести на следующую строчку. | * Не надо писать if, for и while в одну строчку. Если внутри for'а ничего не делается, ";" следует перенести на следующую строчку. | ||
− | * Есть замечательное соглашение, что функции | + | * Есть замечательное соглашение, что функции сравнения int compare(a, b) возвращают число, меньшее нуля, если a < b, равное нулю, если a = b, и большее нуля, если a > b. Не надо изобретать своих неинформативных возвращаемых значений. |
− | * Следует объявлять переменные как можно ближе к месту первого использования. Это, во-первых, уменьшает число переменных в данной области видимости до тех, которые действительно необходимы, во-вторых, если первое использование — это инициализация, это уменьшает время проведенное переменной в неинициализированном состоянии, что уменьшает вероятность ей в таком состоянии быть использованной. | + | * Следует объявлять переменные как можно ближе к месту первого использования. Это, во-первых, уменьшает число переменных в данной области видимости до тех, которые действительно необходимы, во-вторых, если первое использование — это инициализация, это уменьшает время, проведенное переменной в неинициализированном состоянии, что уменьшает вероятность ей в таком состоянии быть использованной. |
* Пользуйтесь нормальными словарями. Хотя бы lingvo.yandex.ru. Там можно узнать, например, который из переводов слов «площадь» или «больше» нужен. Там же можно посмотреть, что по-английски вычитание пишется как subtraction, а не substraction или еще как-нибудь. | * Пользуйтесь нормальными словарями. Хотя бы lingvo.yandex.ru. Там можно узнать, например, который из переводов слов «площадь» или «больше» нужен. Там же можно посмотреть, что по-английски вычитание пишется как subtraction, а не substraction или еще как-нибудь. | ||
* После if, for и while перед «(» должен быть пробел. | * После if, for и while перед «(» должен быть пробел. | ||
* После идентификатора функции перед «(» пробел не нужен. Как в использовании, так и в объявлении и определении. | * После идентификатора функции перед «(» пробел не нужен. Как в использовании, так и в объявлении и определении. | ||
* Если в заголовочном файле определяется класс, то название этого файла должно совпадать с названием класса с точностью до расширения. | * Если в заголовочном файле определяется класс, то название этого файла должно совпадать с названием класса с точностью до расширения. | ||
− | * Следует использовать списки инициализации, | + | * Следует использовать списки инициализации там, где это возможно. |
− | * Для определения того, чем является символ (цифра, буква, пробельный символ) есть функции issomething из <cctype>. | + | * Для определения того, чем является символ (цифра, буква, пробельный символ), есть функции issomething из <cctype>. |
− | * Для подключения заголовочных файлов, пришедших из C следует использовать <cheader>, а не <header.h>. В <cheader> все обернуто в пространство имен std, что не может не радовать. Да и вообще, header.h из C в состоянии deprecated. | + | * Для подключения заголовочных файлов, пришедших из C, следует использовать <cheader>, а не <header.h>. В <cheader> все обернуто в пространство имен std, что не может не радовать. Да и вообще, header.h из C в состоянии deprecated. |
− | * Не надо объединять переменные в объявлениях по типу. Одновременно можно объявлять только такие небольшие группы как x,y, или a,b,c или еще что-нибудь подобное. | + | * Не надо объединять переменные в объявлениях по типу. Одновременно можно объявлять только такие небольшие группы, как x,y, или a,b,c или еще что-нибудь подобное. |
* Не надо делать using в заголовочных файлах вне классов и функций. Не надо добавлять в глобальную область видимость то, что никто не просил. | * Не надо делать using в заголовочных файлах вне классов и функций. Не надо добавлять в глобальную область видимость то, что никто не просил. | ||
* Не надо писать бессмысленные комментарии в духе // constructors, или // arithmetic operators, или еще чего-нибудь подобного. Это и так очевидно. | * Не надо писать бессмысленные комментарии в духе // constructors, или // arithmetic operators, или еще чего-нибудь подобного. Это и так очевидно. | ||
Строка 27: | Строка 27: | ||
* По возможности не следует использовать глобальные переменные. За их состоянием сложнее следить. | * По возможности не следует использовать глобальные переменные. За их состоянием сложнее следить. | ||
* В конце операторов ввода/вывода следует восстанавливать измененные параметры потока. | * В конце операторов ввода/вывода следует восстанавливать измененные параметры потока. | ||
− | * Лучше явно подключать необходимые заголовочные файлы. Например, если main.cpp используется iostream, то напишите явно #include <iostream>, даже несмотря на то, что он подключается в big_int.h, который подключается в main.cpp, что в принципе достаточно для работы. | + | * Лучше явно подключать необходимые заголовочные файлы. Например, если в main.cpp используется iostream, то напишите явно #include <iostream>, даже несмотря на то, что он подключается в big_int.h, который подключается в main.cpp, что в принципе достаточно для работы. |
* Не надо называть одинаковые вещи разными именами и наоборот. Если хочется иметь функцию-геттер size() и private поле size, назовите поле size_. | * Не надо называть одинаковые вещи разными именами и наоборот. Если хочется иметь функцию-геттер size() и private поле size, назовите поле size_. | ||
* Не стоит копировать чужой код, особенно, не думая. | * Не стоит копировать чужой код, особенно, не думая. | ||
− | * Лучше подключать сначала внешние заголовочные файлы, и только потом свои. Желательно каждую группу (boost, stl, свои, ...) выделять пустыми строками. Если внутренние заголовочные файлы (которые часто добавляют все в глобальное пространство имен) будут объявлены до внешних (в которых все обычно в каком-нибудь неймспейсе), то может случится конфликт имен. | + | * Лучше подключать сначала внешние заголовочные файлы, и только потом — свои. Желательно каждую группу (boost, stl, свои, ...) выделять пустыми строками. Если внутренние заголовочные файлы (которые часто добавляют все в глобальное пространство имен) будут объявлены до внешних (в которых все обычно в каком-нибудь неймспейсе), то может случится конфликт имен. |
* Стоит делать конструктор от одного аргумента explicit, если его не предполагается использовать для неявного приведения. Неявного приведения разных сущностей быть не должно, int → big_int — OK, string → big_int — плохо. | * Стоит делать конструктор от одного аргумента explicit, если его не предполагается использовать для неявного приведения. Неявного приведения разных сущностей быть не должно, int → big_int — OK, string → big_int — плохо. | ||
* В заголовочных файлах у сигнатур функций необходимо писать имена аргументов, чтобы можно было понять, который что значит. Возможным исключением являются операторы, для которых это и так достаточно очевидно. | * В заголовочных файлах у сигнатур функций необходимо писать имена аргументов, чтобы можно было понять, который что значит. Возможным исключением являются операторы, для которых это и так достаточно очевидно. | ||
− | * Значения аргументов по умолчанию должны | + | * Значения аргументов по умолчанию должны находиться в заголовочных файлах, а не в файлах с реализацией. |
− | * В c++ нет гарантий на то, как будет | + | * В c++ нет гарантий на то, как будет соотноситься размер указателя и какого-нибудь интегрального типа. Поэтому для swap'а union'ов недостаточно обменять те члены, которые, как вам кажется, не меньше по размеру остальных. Наиболее правильным решением является создание именованного union'а, к которому можно применить std:swap. |
− | * Конструктор копирования и оператор присваивания умеют создаваться автоматически. Если для класса нет необходимости писать специальную версию этих функций и нет каких-то других причин для этого, то лучше и не | + | * Конструктор копирования и оператор присваивания умеют создаваться автоматически. Если для класса нет необходимости писать специальную версию этих функций и нет каких-то других причин для этого, то лучше и не писать. |
− | * Если какой-то из private-членов заканчивается на подчеркивание, то лучше чтобы это выполнялось для всех private-членов. | + | * Если какой-то из private-членов заканчивается на подчеркивание, то лучше, чтобы это выполнялось для всех private-членов. |
* Вокруг бинарных операторов ставятся пробелы (при использовании). | * Вокруг бинарных операторов ставятся пробелы (при использовании). | ||
− | * | + | * Большие объекты (векторы, строчки и т.д.) следует передавать в функцию по константной ссылке, а не по значению, если это возможно. |
* В стандарте нет конструктора от строки у std::exception. Используйте, например, std::runtime_error или еще что-нибудь (см. [http://www.cplusplus.com/reference/std/stdexcept/stdexcept]). | * В стандарте нет конструктора от строки у std::exception. Используйте, например, std::runtime_error или еще что-нибудь (см. [http://www.cplusplus.com/reference/std/stdexcept/stdexcept]). |
Версия 07:16, 19 июня 2011
В этой статье приведены некоторые замечания, которые довольно часто встречаются в работах по C++. Пока никак не упорядочены.
Собственно, замечания:
- Список частых замечаний не прочитан или не осознан.
- Не надо смешивать пробелы и табы для отступов. Необходимо придерживаться строго одного стиля (лучше с пробелами), иначе у кого-нибудь что-нибудь поедет и это будет невозможно читать. Кроме того, таким образом легко заметить копи-паст, который не одобряется.
- Тоже самое с фигурными скобками — придерживайтесь одного стиля.
- Не надо использовать приведение в C-стиле (type)v или type(v) для встроенных типов (интегральные типы, указатеи, ссылки) — с помощью них можно привести практически все что угодно к чему угодно, следует использовать соответствующие C++ аналоги: static_cast, dynamic_cast, reinterpret_cast и const_cast.
- Не надо заменять символы их ascii-кодами — следует писать '0', а не 48.
- Если не предполагается, что переменная должна изменяться, следует объявлять ее константной. Особенно, если это касается сигнатуры функции.
- Лучше не создавать функций void print_something(something const & s, ostream & o), лучше перегружать operator<<, в котором точно не надо выводить в конце перевод строки.
- Есть замечательные стандартные функции, лежащие в <algorithm>. Не следует изобретать велосипеды и писать свои реализации. Наиболее полезные: reverse, copy, swap, fill, max, min.
- Есть только один случай, когда название функции может являться существительным — когда название отражает то, что функция возвращает: например, union, gcd, area и т.д.
- Не надо писать if, for и while в одну строчку. Если внутри for'а ничего не делается, ";" следует перенести на следующую строчку.
- Есть замечательное соглашение, что функции сравнения int compare(a, b) возвращают число, меньшее нуля, если a < b, равное нулю, если a = b, и большее нуля, если a > b. Не надо изобретать своих неинформативных возвращаемых значений.
- Следует объявлять переменные как можно ближе к месту первого использования. Это, во-первых, уменьшает число переменных в данной области видимости до тех, которые действительно необходимы, во-вторых, если первое использование — это инициализация, это уменьшает время, проведенное переменной в неинициализированном состоянии, что уменьшает вероятность ей в таком состоянии быть использованной.
- Пользуйтесь нормальными словарями. Хотя бы lingvo.yandex.ru. Там можно узнать, например, который из переводов слов «площадь» или «больше» нужен. Там же можно посмотреть, что по-английски вычитание пишется как subtraction, а не substraction или еще как-нибудь.
- После if, for и while перед «(» должен быть пробел.
- После идентификатора функции перед «(» пробел не нужен. Как в использовании, так и в объявлении и определении.
- Если в заголовочном файле определяется класс, то название этого файла должно совпадать с названием класса с точностью до расширения.
- Следует использовать списки инициализации там, где это возможно.
- Для определения того, чем является символ (цифра, буква, пробельный символ), есть функции issomething из <cctype>.
- Для подключения заголовочных файлов, пришедших из C, следует использовать <cheader>, а не <header.h>. В <cheader> все обернуто в пространство имен std, что не может не радовать. Да и вообще, header.h из C в состоянии deprecated.
- Не надо объединять переменные в объявлениях по типу. Одновременно можно объявлять только такие небольшие группы, как x,y, или a,b,c или еще что-нибудь подобное.
- Не надо делать using в заголовочных файлах вне классов и функций. Не надо добавлять в глобальную область видимость то, что никто не просил.
- Не надо писать бессмысленные комментарии в духе // constructors, или // arithmetic operators, или еще чего-нибудь подобного. Это и так очевидно.
- Следует совмещать объявление и инициализацию объекта там, где это возможно.
- По возможности не следует использовать глобальные переменные. За их состоянием сложнее следить.
- В конце операторов ввода/вывода следует восстанавливать измененные параметры потока.
- Лучше явно подключать необходимые заголовочные файлы. Например, если в main.cpp используется iostream, то напишите явно #include <iostream>, даже несмотря на то, что он подключается в big_int.h, который подключается в main.cpp, что в принципе достаточно для работы.
- Не надо называть одинаковые вещи разными именами и наоборот. Если хочется иметь функцию-геттер size() и private поле size, назовите поле size_.
- Не стоит копировать чужой код, особенно, не думая.
- Лучше подключать сначала внешние заголовочные файлы, и только потом — свои. Желательно каждую группу (boost, stl, свои, ...) выделять пустыми строками. Если внутренние заголовочные файлы (которые часто добавляют все в глобальное пространство имен) будут объявлены до внешних (в которых все обычно в каком-нибудь неймспейсе), то может случится конфликт имен.
- Стоит делать конструктор от одного аргумента explicit, если его не предполагается использовать для неявного приведения. Неявного приведения разных сущностей быть не должно, int → big_int — OK, string → big_int — плохо.
- В заголовочных файлах у сигнатур функций необходимо писать имена аргументов, чтобы можно было понять, который что значит. Возможным исключением являются операторы, для которых это и так достаточно очевидно.
- Значения аргументов по умолчанию должны находиться в заголовочных файлах, а не в файлах с реализацией.
- В c++ нет гарантий на то, как будет соотноситься размер указателя и какого-нибудь интегрального типа. Поэтому для swap'а union'ов недостаточно обменять те члены, которые, как вам кажется, не меньше по размеру остальных. Наиболее правильным решением является создание именованного union'а, к которому можно применить std:swap.
- Конструктор копирования и оператор присваивания умеют создаваться автоматически. Если для класса нет необходимости писать специальную версию этих функций и нет каких-то других причин для этого, то лучше и не писать.
- Если какой-то из private-членов заканчивается на подчеркивание, то лучше, чтобы это выполнялось для всех private-членов.
- Вокруг бинарных операторов ставятся пробелы (при использовании).
- Большие объекты (векторы, строчки и т.д.) следует передавать в функцию по константной ссылке, а не по значению, если это возможно.
- В стандарте нет конструктора от строки у std::exception. Используйте, например, std::runtime_error или еще что-нибудь (см. [1]).