Язык программирования С++ Стандарт кодирования Версия 0.03 20 ноября 2011 StartUp Company Язык программирования С++. Стандарт кодирования. Версия 0.03 2 Условные обозначения. + - принято * - рекомендовано. 1. Структура проекта 1.1. + Любой проект состоит из каталогов Inc, Src, Res, Debug, Release, Help, Test, Doc. В директории проекта лежат все файлы, по умолчанию генерируемые при создании проекта. В директории Src лежат все исходники программы, за исключением заголовочных файлов. В директории Inc лежат все заголовочные файлы проекта. В директории Res – ресурсы проекта. Help – помощь, если есть. Test – проекты, программы, испольующиеся для отладки проекта или компонентов проекта. Doc – документация к проекту – описание проекта, техническое задание, описание алгоритмов, отдельных компонетнов и т.п. Debug, Release – диретории содержащие временные файлы при компиляции проекта. Все проекты имеют общую директорию ThirdParty – в которую складываются все внешние заголовочные файлы, файлы библиотек, sdk и примеры. 1.2. + Файлы должны иметь стандартные расширения. файлы С - c; файлы С++ - cpp; заголовочные файлы - h, .hpp; файлы ресурсов - rc; 1.3. + Имя файла должно быть уникальным и соответствовать содержимому. 1.4. * Файл не должен содержать более 2000 строк. 2. Комментарии (поправить под doxygen) Язык программирования С++. Стандарт кодирования. Версия 0.03 3 2.1. + Язык комментариев – один язык комментариев (английский или русский) в пределах одного логического модуля (класс, группа классов). 2.2. + Используйте "//" для комментариев. Допускается использование /* нестрочных комментариев */ для комментирования параметров по умолчанию. 2.3. + Не используйте сокращения в комментариях. 2.4. + Комментарии должны быть осмысленными. Не комментируйте очевидное. 2.5. + Располагайте код и комментарии вместе. Сверху или справа от кода. 2.6. + Комментарии должны быть выровнены по вертикали. 2.7. + Комментарии должны располагаться на одном уровне с кодом. Пример: // перебор объектов for( int i = 0; i < 10; i++) { // сравнение объектов для получения индекса этого объекта ... } 2.8. + Обязательно комментирование класса, структуры, перечислений, определений типов. Пример комментария к классу: /*! \class CGameRender \brief Рисователь игры */ class CGameRender … Пример комментария к определению типа: /*! \typedef ScreenRendersMap_t \brief Тип отображения экранных рисователей */ typedef std::map< std::type_info, IScreenRender::shared_ptr > ScreenRendersMap_t; В общем случае комментарий имеет вид: /*! \<class\struct\enum\typedef> <Имя> \brief <Описание назначения> */ Язык программирования С++. Стандарт кодирования. Версия 0.03 4 Перед объявлением метода должно быть краткое описание назначения метода, входных параметров, бросаемых исключений, выходного значения в соответствии с правилами оформления Doxygen. При этом могут использовать как полная форма, так и сокращенная. Полная форма подразумевает обязательное наличие таких блоков (если они допустимы): \brief, \param, \tparam(для шаблонных параметров), \throw, \return(кроме типа void). Краткая форма может использоваться, если для описания достаточно наличие одного из блоков \brief или \return. Пример полной формы: /*! \brief возвращает некоторе значение по указанному индексу. \tparam TValue тип возвращаемого значения \param cnIdx индекс, по которому берётся значение \throw std::runtime_error в случае, если cnIdx выходит за диапазон допустимых значений \return некоторое значение по индексу */ Template< typename TValue > TValue GetSomeValue( const std::size_t cnIdx ); Пример краткой формы: //! \return true, если перемещать объект нельзя, иначе false bool IsMoveable() const; Обязательно комментирование объявлений полей класса. Пример: ScreenRendersMap_t m_mapRenders; //!< Рисователи экранов Перед определением процедур никаких окмментариев быть не должно. Язык программирования С++. Стандарт кодирования. Версия 0.03 5 3. Форматирование текста 3.1. + Используйте аккуратные столбцы. Пример: int i; OneStruct Basic; VeryLongClassName VeryImportantValue; 3.2. + Один оператор в строке. Неправильно if (a > b) return true; Правильно if (a > b) return true; Допускается else if if (a > b) return true; else if (a < b) return false; … 3.3. + Предикатная форма разбивки длинных выражений. Пример: if( VeryLongValueName1 < VeryLongValueName2 || VeryLongValueName3 >= VeryLongValueName1 ) { ...; } 3.4. + Разделяйте пробелами операции и переменные, за исключением операций ., -> и унарных операций [], (), *, &, ~, ++, --. Пример: int *pIndex; i = 2 * ( j + 1 ) - ptr->Value1 + ptr.Value2 / Array[ 1 ]; if( j <= i ) Пробелы для разделения скобок не обязательны. i = 2 * (j + 1)/rgChan[j]; 3.5. + Используйте отступы в табуляцию равную 4-м пробелам. (Tab = 4) 3.6. + Фигурные скобки выравниваются по левой границе. Пример: Правильно: if( ... ) { for( ; ; ) { ...; } } Язык программирования С++. Стандарт кодирования. Версия 0.03 Неправильно: if (...) { ... } 3.7. + Длина строки не более 95 символов. 6 Язык программирования С++. Стандарт кодирования. Версия 0.03 7 4. Содержимое файлов 4.1. + Содержимое .H-файла должно использоваться в нескольких c или cpp-файлах. 4.2. + Заголовочный файл не должен содержать более одного описания класса (исключение - описание вспомогательных небольших классов в одном файле с главным или несколько небольших классов, связанных по смыслу). 4.3. + Заголовочный файл и файл с исходным кодом должны содержать комментарии в соответствии с правилами Doxygen. Обязательно наиличие блоков в указаннов порядке: \file, \date, \author, \brief. Пример: /*! \file GameRender.h \date 2011 \author Esik Antony <esik.antony@gmail.com> \brief Содержит объявления связанные с рисователем игры */ 4.4. Устраняйте возможность многократного подключения заголовчных файлов. Для этого необходимо использовать конструктцию #ifnedf-#define-#endif. Имя для гуарда формируется по правилу: __<Аббревиатура проекта>_<Аббревиатура\имя модуля\подпапки>_<Имя заголовочного файла>_H – всё в верхнем регистре. Пример: #ifndef __SUGC_RENDER_GAMERENDER_H #define __SUGC_RENDER_GAMERENDER_H … #endif // __SUGC_RENDER_GAMERENDER_H 4.5. + Если в проекте используются предкомпилированные заловочные файлы, то все включения сторонних библиотек должны быть сделаны в stdafx.h.4.6. + Заголовчные файлы должны быть по максимуму облегчены. Это означает, что они не должны включать в себя другие заголовчные файлы. Если в объявлении класса используются объекты другого класса, то должны присутствовать опережающие объявления (forward declaration). 4.7. + Не определяйте переменные в .H-файле. 4.8. + Не объявляйте статические функции и объекты(переменные) в заголовочном файле, за исключением статических членов класса. 4.9. + Не используйте макросы (#define). Примеры #define MAX_CHAN 21 -> const int MAX_CHAN = 21; #define CClassPtr CClass* -> typedef CClass* CClassPtr; #define ABS(x) (x > 0) ? x : -x -> template <class T> T Abs(const T& x) { return x > 0 ? x : -x; } и т.д Язык программирования С++. Стандарт кодирования. Версия 0.03 8 Язык программирования С++. Стандарт кодирования. Версия 0.03 9 5. Названия переменных, макросов, функций, классов и т.п. 5.1. + Все имена должны начинаться с заглавной буквы. Имена используемые в программе для классов, структур, типов, переменных, полей классов, перечислений должны быть именами существительными английского языка. 5.2. + В именах переменных используйте стандартные префиксы. Префиксы принадлежности переменных g_ Префикс для глобальной переменной m_ Для члена класса s_ Статический член класса Префиксы типа переменной b BOOL w Word (слово) ch символ, char, TCHAR by Byte(Байт) unsigned char sz Указатель на первый символ строки ANSI заканчивающейся нулем. wsz Указатель на первый символ строки UNICODE, заканч-ся нулем. dw DWORD, double word or unsigned long h Handle n ui i l d,dbl f,flt p rc,rect size clr dc pt bm, bmp str,s wnd obj dlg std::size_t unsigned int, unsigned short int, short Long double float префикс указателя * CRect, RECT CSize, SIZE Цвет COLORREF CDC CPoint, POINT CBitmap CString, строки CWnd, window Object objUserTable Dialog, CDialog Суффиксы Indx, Idx обозначает индекс Num обозначает номер 5.3 + Имена методов и ф-ий должны начинаться с глагола. Язык программирования С++. Стандарт кодирования. Версия 0.03 10 5.4 + Имена классов должны содержать приставку «C», структур – «S», перечислений «E». 5.5 + Имена определений типов (typedef) не должны содержать никаких приставок, но должны иметь суффикс _t. Пример: /*! \typedef ScreenRendersMap_t \brief Тип отображения экранных рисователей */ typedef std::map< std::type_info, IScreenRender::shared_ptr > ScreenRendersMap_t; 5.6. + В функциях получения данных используются префиксы Get. В функциях присвоения - Set. В функциях инициализации - Create. Для функций возвращающих булевское значение используйте вопросительную форму. Например: bool IsCreated(void); int GetSize(void); bool SetSize( int Number ); 5.7. + Имена макросов пишутся ЗАГЛАВНЫМИ_БУКВАМИ. 5.8. + Запрещается использование нецензурных слов в именах используемых в программе. Язык программирования С++. Стандарт кодирования. Версия 0.03 11 6. Методы и классы 6.1. + Для доступа к переменным – членам класса используйте функции доступа. 6.2. + Функции доступа и ретрансляции должны быть inline. 6.3. + Функции, которые не могут изменять содержимое класса, должны объявляться как const. Пример: int GetSize(void) const; 6.4. + При передаче в функцию объектов, для использования (не модификации), передавайте их как константную ссылку. Пример: void CreateObject( const ObjectData& rData ); 6.5. + При передаче в функцию объектов, на модификацию, передавайте их как ссылку. Пример: void CreateObject( ObjectData &objData ); 6.6. + Всегда определяйте возвращаемое значение функции. Пример: // Плохо GetSize(void) const; // Хорошо int GetSize(void) const; 6.7. + Используйте inline только тогда когда это действительно необходимо. 6.8. + Функции с разными параметрами(входными или выходными) должны иметь разные имена. 6.9. + Никогда не перегружайте не виртуальные функции. 6.10 + Не использовать коды возврата из ф-ий\методов, если в ходе работы метода выясняется, что достигнута ошибочная, неразрешимая ситуация – он должен бросить исключение, для обработки его на более высоком уровне. Язык программирования С++. Стандарт кодирования. Версия 0.03 12 7. Конструкторы и деструкторы 7.1. + Не использовать malloc и free – вместо них new и delete.7.2. + Учитывайте, что при выделении памяти может быть брошен exception std::bad_alloc. 7.3. + Если использовался new [], то при удалении должен быть использован delete []. Причём на созданный оператором new [] массив объектов должен указывать указатель на тип создаваемых объектов, чтобы delete [] мог корректно удалить все объекты, иначе утечка памяти, т.е. нельзя, чтобы на выделеный по new[] массив объектов ссылался указатель базового класса.7.4. + Если переопределяется new, то должен быть переопределен delete. 7.5. + Отделяйте интерфейсные объекты от данных. Для объектов данных (особенно если они используют динамическое выделение памяти) определяйте конструктор копирования и операцию присвоения. 7.6. * Деструктор объявляется виртуальным. 7.7. + Конструктор и деструктор не могут быть inline. 7.8. + Не используйте глобальные и статические объекты в конструкторах и деструкторах. 7.9. + Для инициализации данных – членов класса используйте список инициализации. 7.10. + Оператор присвоения должен возвращать константную ссылку на объект. Пример: const Obj& operator=( const Obj& rObj ) { if( this != &rObj ) { // Копирование ... } return *this; } 7.11. + Присваивание самому себе должно работать. 7.12. + Только деструктор не должен генерировать исключения. Конструктор может это делать. 7.13. * Старайтесь не выделять память в конструкторе. Язык программирования С++. Стандарт кодирования. Версия 0.03 13 8. Исключения 8.1 + Для сигнализации ошибочных ситуаций в коде используйте исключения. 8.2 + Все пользовательские исключения должны так или иначе наследоваться от std::exception. 8.3 + Бросать исключения по значению, ловить по константной ссылке. 8.4 * Все места потенциального выброса исключения в коде методов стоит отмечать комментарием // exception 8.5 + Методы не должны содержать спецификации типов выбрасываемых исключений, кроме спецификации, что метод вовсе не кидает исключений: throw(). 8.6 + Если логика метода не подразумевает выброса исключений (в том числе и методы, которые вызываются внутри метода), то это должно быть отражено спецификацией throw() в объявлении метода. Язык программирования С++. Стандарт кодирования. Версия 0.03 14 9. Общие 9.1. + Код после оператора case должен завершатся break или return. Пропуск этих операторов должен комментироваться. Пример: switch( i ) { case 1: return true; case 2: // break пропущен специально case 3: ...; break; default: return false; } 9.2. + Определение оператора switch должно всегда завершатся default. Пример: см. 8.1. 9.3. * Если ваша функция состоит из нескольких условий if, которые возвращают значения используйте используйте else. Данный способ предотвратит вас от ошибки на этапе компиляции, если вы забыли вставить в одном из условий return. Впрочем вы можете не писать else если структура функции не включает несколько уровней вложенности. Неправильно if (x < 0.0) { if (long(x) == x) { … return long(x); } … return long(x) - 1; } … return long(x); Правильно if (x < 0.0) { if (long(x) == x) { … return long(x); } else { … return long(x) - 1; } Язык программирования С++. Стандарт кодирования. Версия 0.03 15 } else { … return long(x); } Правильно if ( a < b) return false; … if (a < c) return false; … return true; 9.4. + Избегайте длинных и сложных функций. Если функция включает 15 вложенных операторов if, то при тестировании нужно проверить 215 комбинаций. 9.6. + Избегайте не именованных перечислений. При объявлении переменных используйте тип enum. Пример: enum ETestEnum { TE_None = -1, TE_First = 0, TE_Second = 1 }; 9.7. + В enum должена быть задана неопределённая ситуация. 9.10. + При описании булевых переменных используйте встроенный тип bool. Присвоения делаются с помощью true и false. Проверяйте возвращаемое значения только на сравнение с FALSE, поскольку многие функции возвращают отличное от нуля значение (не обязательно TRUE), если функция выполнена успешно. 9.11. + Заменяйте числа константами там, где это иммет смысл. 9.12. + Пустой цикл должен комментироваться. Пример: for( char *pStr = Name; *pStr != ’.’ && *pStr != 0; pStr++ ); // пустой цикл 9.13. + Ваш исходный код не должен содержать warning-и на максимальном уровне предупреждений(4-м). 9.14. * Если переопределяете виртуальную функцию, то в объявлении всегда пишите, что она виртуальна.