Randy Charles Morin
------------------------------------------------------------
C++ Coding Standard
by MiddleWorld SoftWare
1. INTRODUCTION 2
2. FILE NAMING CONVENTIONS 4
3. IDENTIFIER NAMING CONVENTIONS 6
4. TYPE NAMING CONVENTIONS 9
5. DOCUMENTATION 10
6. CODING STYLE 12
7. CONCEPTS 15
8. SOURCE CODE DEPENDANCIES 20
9. MISCELLANEOUS 24
10. GLOSSARY 25
1. Introduction
In October of 1996, we decided that a coding standard should be
developed that is effective, usable, complete and structured. Our
efforts will be guided towards making a C++ coding standard that has
these missing features.
· Explanation
· Effectiveness
· Usability
· Completeness
· Structure
1.1 Explanation
Whenever possible, the standard will be explained, preferably in
detail. References to popular text books were occasionally
substituted for explanation. The follow text books were commonly
used...
· Effective C++ by Scott Meyers, Addison-Wesley.
· More Effective C++ by Scott Meyers, Addison-Wesley.
· Large-Scale C++ Software Design by John Lakos, Addison-Wesley.
1.2 Effectiveness
It is important that the coding standard be effective. Effective for
this project means that the coding standard actually reduces
development cost, increases development quality and makes everybody
happy.
1.3 Usability
Usability is also very important. If your coding standard is simply
too cumbersome, then usability will become an issue and developers
will stop following the standard. Usability means that developers do
not feel overwhelmed by the standard nor do they find it difficult to
follow.
1.4 Completeness
Completeness is a quality that very few C++ coding standards contain.
Completeness means the coding standard discusses all important coding
standard issues.
1.5 Structure
Structure is extremely important and is an important subset of
usability. If the coding standard is not structured for easy
reading, then you will find that the unusable.
1.6 Sections
The standard will be divided into sections. Each section will tackle
a particular set of standards. Each section will have two
subsections. The first subsection will discuss rules and the second
subsection will discuss suggestions. Rules are standards that can
easily be followed and are very effective. Suggestions are standards
that are more difficult for developers to implement and accept.
· File naming conventions
· Identifier naming conventions
· Type naming conventions
· Documentation
· Coding Style
· Concepts
· Source code dependancies
· Miscellaneous
1.7 Conflicts
Conflicts will no doubt arise between two of the major qualities we
hope to incorporate. When these conflicts arise it is important to
know that there is always middle ground.
Conflicts will also arise where approximately half of the development
community have adopted one standard and half have adopted another
standard. If both standards are equally effective, then one will be
chosen and lengthy debates will be avoided. It is more important to
have a standard, then to squabble.
2. File naming conventions
2.1 Rules
a Source files will have filename extension identifying their type.
File Type Filename Extension
C and C++ header file h
C implementation file c
C++ implementation file cpp
C++ inline file inl
Ms-Windows Bitmap file bmp
Ms-Windows Dialog resource script file dlg
Ms-Windows Icon file ico
Ms-Windows Module definition file def
Ms-Windows Resource header file rh
Ms-Windows Resource script file rc
Ms-Windows Wave file wav
b For every C++ implementation file, a formal declaration will be
contained in a C++ header file of the same filename, that is,
string.h and string.cpp.
c All inline functions will be contained in a inline file or header
file of the same filename as the implementation file, that is,
string.inl and string.h.
d For every ms-windows resource file and ms-windows dialog resource
file, a formal declaration will be contained in a resource header
file of the same filename, that is, string.rh and string.rc.
e Source files will have filename suffixes identifying their object type.
Object Type Filename Suffix
Application app
Button Control btn
Checkbox Control kb
Combobox Control cb
Dialog dlg
Document Object doc
Edit Control ed
Gauge Control ga
Groupbox Control gb
Listbox Control lb
Radio Button Control rb
Scrollbar Control sb
Slider Control sl
Static Control st
View Object vw
Window wnd
2.2 Suggestions
a Dialog templates will be contained in dialog resource file of the
same filename as the implementation file. This is not possible when
a dialog template is shared by more than one implementation.
b Icons that are specific to an module will be contained in an icon
file of the same filename as the entry-point implementation file.
This is not possible when more than one icon are specific to the same
module or when an icon is shared by more than one implementation.
3. Identifier naming conventions
3.1 Rules
a Identifier function names must begin with at least one uppercase letter.
b Identifier variable names, with the exception of resource
identifiers must begin with at least one lower case letter.
c Variable identifiers will have prefix identifying there scope.
Variable Scope Identifier Prefix
Compiler Constant [none]
Global Variable g_
Local Variable [none]
Member Variables m_
Static Member Variables sm_
Static Variables s_
d Variable identifers will have secondary prefix identifying there type.
Variable Type Indentier Prefix
Arrays a
Bitmap Identifiers IDB_
Bitmaps bmp
C++ strings str
Character strings s
Chars c
Combobox Controls cb
Constants c
Control Identifiers IDC_
Device Context dc
Dialog Identifiers IDD_
Dialogs dlg
Documents doc
Double d
Double Word dw
Edit Controls ed
Float f
Function fn
Gauge Controls ga
Groupbox Controls gb
Handle h
Icon Identifiers IDI_
Icons icon
Integers i
List views lv
Listbox Controls lb
Long Double ld
Long Integers l
Null-terminated strings sz
Pointer p
Pointers to Pointers pp
Property Sheet ps
Reference r
Resource Identifiers ID_
Scrollbar Controls sb
Short Integers n
Slider Controls sl
Static Controls st
String Identifiers IDS_
Tree views tv
unsigned u
Views vw
Windows wnd
Word w
3.2 Suggestions
a The identifier will be suffixed with a description of the
identifiers intended usage. The description will not include
underscores and the first letter of each word will be capitalized to
show word breaks. The description is not intended for local
identifiers that are used simply as temporaries, counters or place
holders.
b Local temporaries, counters and place holders will be named
according to their type.
Local Type Identifier Name Secondary Name
Arrays a
Bitmaps bmp
C++ strings str
Character strings s
Chars c
Combobox Controls combobox
Constants c
Dialogs dlg
Documents doc
Edit Controls edit
Gauge Controls gauge
Groupbox Controls groupbox
Icons icon
Integers i j
List views listview
Listbox Controls listbox
Long Integers l
Null-terminated strings sz
Pointer p q
Pointers to Pointers pp
Scrollbar Controls scrollbar
Short Integers n
Slider Controls slider
Static Controls static
Tree views treeview
Views view
Windows wnd
4. Type naming conventions
4.1 Rules
a Type names begin with at least one upper case letter.
b Class names will be prefixed with one to three letters, the first
letter is upper case and second and third letters are lower case.
The prefix should describe the source of the class.
c The class prefix “C” is reserved for Microsoft’s usage.
d The class prefix “T” is reserved for Borland’s usage.
e Class names will have suffixes identifying their class type.
Class Type Class Suffix
Bitmap Bmp
Button Control Btn
Checkbox Control Checkbox
Combobox Control Combobox
Dialog Dlg
Documents Doc
Edit Control Edit
Gauge Control Gauge
Groupbox Control Groupbox
List views ListView
Listbox Control Listbox
Radio Button Control RadioButton
Scrollbar Control Scrollbar
Slider Control Slider
Static Control Static
Tree views TreeView
Views View
Window Wnd
4.2 Suggestions
a The class prefix “M” is reserved for MiddleWorld SoftWare’s usage.
5. Documentation
5.1 Rules
a All implementation files, header files and resource files should
have a document header. The document header should contain a title
and a description.
/*
Object Title
This object implements an object that performs methods to emulate an
object of the same type.
© MiddleWorld SoftWare, 1996
*/
b All function definitions should have a single line or multiple line
document header.
// this function returns zero
int func()
{return 0;};
c Thoroughly document declaration files that will be used by client
developers. Each function declaraction should have a single or
multiple line document header, and every function parameter should be
on separate lines and have an additional end-of-line comment.
class MClass
{
// this function returns the sum
int func( int a, // this is the first parameter
int b); // this is the second parameter
};
d Use the C++ style single line comment preprocessor statement in
place of the C style comment preprocessor statements, except when
commenting part of line that does not occur at the end-of-the-line or
when commenting a more then one consecutive lines. See Item 4 of
“Effective C++” by Scott Meyers.
int i; // suggested
int i; /* not suggested */
int func(int /*i*/) // suggested
/* not suggested */
// suggested
/*
suggested
suggested
suggested
*/
e Parameter names should not be excluded from function declarations
or function definitions. To remove compiler warnings, comment out
the parameter name.
f(int /* i */) // suggested
f(int) // not suggested
5.2 Suggestions
a Copyright notices should be located in the document header.
6. Coding Style
6.1 Rules
a Header files must contain sentinels, that is, directives to prevent
against multiply inclusion. The project sentinel, filename and
extension are delimited by the underscore character. A header file
named “filename.h” in the project called “project” must have the
following sentinels...
#ifndef PROJECT_FILENAME_H
#define PROJECT_FILENAME_H
...
#endif
b Header files should not require the prior inclusion of other header
files. The following implementation file should compile without
error for every header file...
#include <pch.h> // pre-compiled header file
#include “yours.h” // every header file
c The project sentinel CLASSLIB_ and __ are reserved for the standard
libraries.
d The project sentinel OWL_ is reserved for Borland’s usage.
e The function return type should located on the same line as the
function name.
int func() // suggested
int
func() // not suggested
f Limit line length to 120 characters.
g Set tabs to 3 spaces.
h Indent with tabs.
i Never use a goto statement.
j Use new and delete in place of malloc and free. See Item 3 of
“Effective C++” by Scott Meyers.
k Member initializations should be indented and on separate lines.
MyObject::MyObject()
: m_i(0),
m_j(1)
{};
l Code blocks have braces in the same column and on separate lines.
Contained code is indented. Single line and empty code blocks need
not follow this rule.
{
...
}; // suggested
{}; // suggested for empty code blocks only
{return 0;}; // suggested for single line code blocks only
m Throw exceptions in place of calling the assert function.
assert(x); // not suggested
if (!x) throw MException ; // suggeste
n Inline member functions should not be defined in the class definition.
class MClass
{
int func()
{return 0;};
} // not suggested
class MClass
{
int func();
}
inline int MClass::func()
{return 0;}; // suggested
o Inline functions should be used in place of defined precompiler
macros. See Item 1 of “Effective C++” by Scott Meyers.
#define MAX(a,b) ((a)>(b)?(a):(b)) // not suggested
template<class T>
inline T& Max(T& a, T& b)
{ return a > b ? a : b; }; // suggested
p When a constant is used in several implementation files, use static
class member constant identifiers in place of defined precompiler
constants. When a constant is used in one implementation files, use
static member constant identifiers of the encapsulation structure in
place of defined precompiler constants. See Item 1 of “Effective
C++” by Scott Meyers.
#define OK 1 // not suggested
int MClass::sm_iOK = 1; // suggested
q Use C++ style casting in place of C style casting. See Item 2 of
“More Effective C++” by Scott Meyers.
double d = (double)i; // not suggested
double d = static_cast<double>i; // suggested
6.2 Suggestions
a Attempt to use the return codes int and bool wherever possible.
b All return codes returned as integers should be defined as static
const integers. If the return codes are shared between
implementation files, the return code should be a public member
variable, otherwise the return code should be declared and defined
solely in the singular implementation file.
c Use static constant integers in place of enumerations defined in
the declaraction file. See Removing Enumerations in “Large-Scale C++
Software Design” by John Lakos.
d The project sentinel MW_ is reserve for MiddleWorld SoftWare’s usage.
e Header files should have the following organization; sentinel,
documentation header, inline include directive, external include
directives, internal include directives, forward declarations, class
declaration, sentinel.
f Implementation files should have the following organization;
pre-compiled header directives, documentation header, object include
directive, external include directives, internal include directives,
encapsulating declaration, other declarations, static member variable
definitions, constructors and destructors, member functions.
g Classes declarations should have the following ordered sections;
encapsulated declarations, static member variables, constructors and
destructors, virtual methods, constant methods, other methods,
private encapsulation structure.
h Each class declaration section should begin with a one-line comment
indicating the section title.
i Use the following portable data types.
Portable Data Type Description
INT8 8-bit integer
UINT8 8-bit unsigned integer
INT16 16-bit integer
UINT16 16-bit unsigned integer
INT32 32-bit integer
UINT32 32-bit unsigned integer
INT64 64-bit integer
UINT64 64-bit unsigned integer
7. Concepts
7.1 Rules
a Where subclasses may be derived from a base class, the base class
should have a virtual destructor. See Item 14 of “Effective C++” by
Scott Meyers.
b Catch exceptions by reference as oppose to by pointer or value.
See Item 13 of “More Effective C++” by Scott Meyers.
c Where a classes default copy constructor or assignment operator are
not adequate, explicitly declare a copy constructor and assignment
operator. Declare the copy constructor and assignment operator
private, if an adequate function cannot be coded. See Item 11 of
“Effective C++” by Scott Meyers.
d Check for assignment to self in the assignment operator. See Item
17 of “Effective C++” by Scott Meyers.
e Have the assignment operator return a reference to *this. See Item
15 of “Effective C++” by Scott Meyers.
f Delete arrays using the delete[] operator. See Item 5 of
“Effective C++” by Scott Meyers.
g When encapsulating a C API, make all functions and data normally
available in the API public in the encapsulation structure.
struct MWindow
{
public:
HWND m_hwnd;
HWND CreateWindow(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hwndParent,
HMENU hmenu,
HANDLE hinst,
LPVOID lpvParam);
...
};
inline HWND MWindow::CreateWindow(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hwndParent,
HMENU hmenu,
HANDLE hinst,
LPVOID lpvParam)
{
m_hwnd = ::CreateWindow(lpszClassName,
lpszWindowName,
dwStyle,
x, y,
nWidth, nHeight,
hwndParent,
hmenu,
hinst,
lpvParam);
return m_hwnd;
};
h Do not add functionality to a C API encapsulating structure.
Inherit from the base functionality and add the functionality to the
subclass.
i Write all C API encapsulating code using inline functions. Writing
API encapsulating code out-of-line would degrade performance.
j Prevent exceptions from leaving destructors. Termination occurs
when a destructor caused by throwing an exception throws a second
exception. See Item 11 of “More Effective C++” by Scott Meyers.
MyObject::~MyObject()
{
... // exception here may cause termination
} // not suggested
MyObject::~MyObject()
{
try
{
...
}
catch(...)
{
}
} // suggested
k Prevent resource leaks in constructors by catching exceptions. See
Item 10 of “More Effective C++” by Scott Meyers.
MyObject::MyObject()
:m_pi(0)
{
m_pi = new int;
... // exception here will cause memory leak
} // not suggested
MyObject::MyObject()
:m_pi(0)
{
try
{
m_pi = new int;
...
}
catch(...)
{
delete m_pi;
throw;
}
} // suggested
l Do not return non-constant references and pointers to private
member data from non-constant methods.
m Never overload AND, OR and COMMA. See Item 7 of “More Effective
C++” by Scott Meyers.
7.2 Suggestions
a Pass or return values by reference as oppose to passing or
returning values by pointer. Two exceptions are... If the value may
be missing (null). If the value is returned as a parameter.
f(MyObject & r) // suggested
f(MyObject * r) // not suggested
f(MyObject * r) {if (r==0)...}; // exception #1
f(MyObject * r) {r=new MyObject;}; // exception #2
b Initialization should be used in place of assignment whenever
possible. See Item 12 of “Effective C++” by Scott Meyers.
int i = 0; // assignment - not suggested
int i(0); // initialization - suggested
MClass::MClass() {i = 0;}; // assignment - not suggested
MClass::MClass() : i(0) {}; // initialization - suggested
c List members in an initialization list in the order in which they
are declared. See item 13 of “Effective C++” by Scott Meyers.
d Avoid returning references and pointers to private member data from
class methods.
e Avoid unhandled exception in functions with exception
specifications, by catching all exceptions. Otherwise, run-time
termination routines will abnormally terminate your program.
int MClass::func() throw(MException &)
{
try
{
...
}
catch (MException & x)
{
throw x;
}
catch (...)
{
// oops! now what!
}
}
f Only static member functions should be called during initialization.
class MClass
{
int i;
static int staticfunc();
int nonstaticfunc();
};
MClass::MClass() : i(staticfunc()) {}; // suggested
MClass::MClass() : i(nonstaticfunc()) {}; // not suggested
g Non-heap allocation is preferable to heap allocation. If the code
between the new and delete operations throws an exception, the object
may not be deleted. If heap allocation is necessary, then attempt
using smart pointers. See Item 9 of “More Effective C++” by Scott
Meyers.
{
MyObject p = new MyObject;
... // exception here will cause leaks
delete p;
} // not suggested
{
MyObject m;
...
} // suggested
{
MyObject p = new MyObject;
auto_ptr<MyObject> ap(p);
...
} // suggested
8. Source code dependancies
See “Large Scale C++ Software Design” by John Lakos.
8.1 Rules
a All global declarations should be contained in header files.
b All non-class definitions should contained in implementation or
inline files.
c All C function prototypes should be wrapped in an extern “C” block.
#ifdef __cplusplus
extern “C” {
#endif
...
#ifdef __cplusplus
}
#endif
d All public identifiers, types and constants should be declare in a
header file.
e Only one public class should be defined or declared in any header
or implementation file.
f All private members should be removed from the class
interface-declaration and redeclared in a encapsulation structure
defined in the implementation file. This does not apply to private
virtual functions. See Fully Insulating Concrete Class in “Large
Scale C++ Software Design” by John Lakos.
class MClass // located in declaration file
{
...
private:
int m_i;
}; // not suggested
class Data; // located in declaration file
class MClass
{
...
private:
Data * m_pData;
}; // suggested
struct Data // located in implementation file
{
int m_i;
};
MClass::MClass()
:m_pData(0)
{
m_pData = new Data;
};
MClass::~MClass()
{
delete m_pData;
};
g Non-static member variables should be declared in an encapsulation
structure.
h Private static member variables should be declared in an
encapsulation structure.
i Private non-virtual methods should be declared in an encapsulation
structure.
j External include files, should use the #include <filename.h>
syntax. Internal include files, should use the #include “filename.h”
syntax.
8.2 Suggestions
a Basic types should be passed by value. Basic types include
integers, floats, double and chars.
b Non-local and non-base-type return values should be returned by
reference or constant reference. Local and base-type return values
should be returned by value. See Item 22 of “Effective C++” by Scott
Meyers.
MClass f()
{
static MClass s_Class;
return s_Class;
}; // not suggested
MClass & f()
{
static MClass s_Class;
return s_Class;
}; // suggested
MClass f()
{
MClass s_Class;
return s_Class;
}; // suggested
MClass & f()
{
MClass s_Class;
return s_Class;
}; // not suggested
int & f()
{
return 0;
}; // not suggested
int f()
{
return 0;
}; // suggested
c If a header file requires the declaration of an external class or
struct, use forward declaration. The is not possible when class is
inherited from, passed by value or returned by value.
class MClass;
int f(const MClass & p);
d Variable identifiers that are not modified should be declared
constant. Both pointer and data should be declared constant when
appropriate. See Item 21 of “Effective C++” by Scott Meyers.
e Function parameters that are not modified by the object should be
declared constant. Both pointer and data should by declared constant
when appropriate. See Item 21 of “Effective C++” by Scott Meyers.
f Avoid using inlines class methods. Member data that should be
hidden in the implementation is almost always made public in the
declaration by allowing inline class methods.
g Methods that do not modify the object should be declared constant.
See Item 21 of “Effective C++” by Scott Meyers.
9. Miscellaneous
9.1 Rules
a Use the iostream library in place of the stdio library. See Item 2
of “Effective C++” by Scott Meyers.
b Use the standard template library in place of proprietary template
libraries.
c Warning and error messages should not be suppressed using
command-line compiler and linker options.
d An object oriented developement procedures should be used.
9.2 Suggestions
a Object libraries should be used. Development organizations should
make public object libraries available to all programmers to prevent
duplication of effort.
b Revision control software and procedures should be used. If such
software or procedures are difficult to use or time-consuming, then
they should be enhanced.
c Software specification documents should be prepared for every
development effort. The specification document should include a
detailed definition of system requirements, required new features and
enhancements, optional new features and enhancements, bug patches and
fixes, and removed features.
d Release test procedures should be developed and followed for every
release version of client libraries and software. A test document
may be prepared with a description of the tests performed, expected
results and actual results. A failed test document should be
returned to the developers for further debugging.
e Release control documents should be prepared for every release
version of client libraries or software. The control document should
include trouble shooting, future enhancements, system requirements,
building the release software, installing the release software, known
bugs, bugs fixed, bugs patched, enhancements, new features and
removed features.
10. Glossary
Base-Type Base types are C++ compiler defined types, that is,
integers, floats and characters.
Declaration files A declaration file is a source file that declares
types and may also define classes, but does not define out-of-line
identifiers. Header files are most often declaration files.
External include files Include files that are not part of the current
coding project. This includes all external library include files.
Internal include files Include files that are part of the current
coding project.
Implementation files An implementation file is a source file that
defines identifiers.
Termination A function called terminate is called whenever a
destructor called during an exception throws a second exception.
This type of program termination is very undesirable.