Язык программирования С++. Стандарт кодирования. Версия

advertisement
Язык программирования С++
Стандарт кодирования
Версия 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. *
Если переопределяете виртуальную функцию, то в объявлении всегда пишите, что она
виртуальна.
Download