Click here to Skip to main content
Click here to Skip to main content

C++ Coding Practices Guide

, 20 May 2008
Rate this:
Please Sign up or sign in to vote.
The article describes C++ coding styles and practices to be followed to develop robust and reliable code that is easily comprehended and maintained by other developers.



To write consistent code comprehended by other developers, you are supposed to follow some coding styles and practices, rather than inventing your own ones. These include naming conventions (on how you name your variables and functions), code and class layout (including tabs, whitespace, brackets placement), imperative const correctness etc... To follow this article, you are supposed to know the basics of OOP and C++. There are some great online resources you may use in addition to this article:

Naming Convention

The first task you encounter when you start to write code is how to name your variables, objects, and functions. The importance of naming conventions can not be underestimated. Providing proper naming will result in self-documenting code, easily comprehended by others. Unless you want to obfuscate the source code, you should follow these guidelines.

Use a name that unambiguously describes a variable or object. A function should contain in its name a verb of the action that it implements.

Linux style (use underscores to separate words, names are lowercase):

int some_variable;
float bar_weight;
unsigned int users_number;
bool is_engine_started;
double circle_area;
double m_circle_area; //class private variable, prepend m_ prefix

void* psome_void_pointer;

const int USERS_NUMBER;

int i, j, n, m, tmp; //some local loops variables, temporary variables

namespace mynamespace;

vector<int> users;
vector<char *> user_names;

class SomeClass;

int do_work(int time_of_day);
float calculate_radius(const Circle& rcircle);
int start_io_manager();
int open_dvd_player();

Windows style (MFC applications, prepend Hungarian prefixes to identify the variable type):

INT nSomeVariable;
FLOAT fBarWeight;
DWORD dwUsersNumber;
BOOL bIsEngineStarted;
DOUBLE dCircleArea;
DOUBLE m_dCircleArea;  //class private variable, prepend m_ prefix

PVOID pSomeVoidPointer;


int i, j, n, m, tmp;  //some local loops variables, temporary variables

namespace MyNameSpace;

vector<int> nUsers;
vector<char *> pszUserNames;

class CSomeClass;

INT DoWork(INT nTimeOfDay);
FLOAT CalculateRadius(const& Circle rCircle);
INT StartIOManager();
INT OpenDvdPlayer(); //if abbreviation takes more than
                     // 2 letters do not capitalize the whole word

.NET platform (Hungarian notation, and prefixes are obsolete):

int someVariable;
float barWeight;
unsigned int usersNumber;
bool isEngineStarted;
double circleArea;
double circleArea; //refer to a class private variable
                   // in code as this->circleArea

void^ someVoidPointer;

const int UsersNumber;

int i, j, n, m, tmp;  //some local loops variables, temporary variables

namespace MyNameSpace;

array<int> users;
array<String> userNames;

class SomeClass;

int DoWork(int timeOfDay);
float CalculateRadius(const& Circle circle);
int StartIOManager();
int OpenDvdPlayer();  //if abbreviation takes more than 2 letters
                      // do not capitalize the whole word


Tabs are 8 spaces, so the indentations are also 8 characters. The whole idea is to clearly define where a block of control starts and ends, and you'll find it a lot easier to see how the indentation works if you have large indentations. It also has the added benefit of warning you when you're nesting your functions too deep.

//very bad
void FaceDetector::estimate_motion_percent(const vec2Dc* search_mask)
  if (search_mask == 0) { m_motion_amount=-1.0f; }
     unsigned int motion_pixels=0;
     unsigned int total_pixels=0;
      for (unsigned int y = get_dy(); y < search_mask->height()-get_dy(); y++) 
       for (unsigned int x=get_dx(); x < search_mask->width()-get_dx(); x++) 
           if ((*search_mask)(y,x)==1) motion_pixels++;
    m_motion_amount = float(motion_pixels)/float(total_pixels);

//very good
void FaceDetector::estimate_motion_percent(const vec2Dc* search_mask)
        if (search_mask == 0)
                m_motion_amount = -1.0f;
        else {
                unsigned int motion_pixels = 0;
                unsigned int total_pixels = 0;
                for (unsigned int y = get_dy(); y < 
                           search_mask->height() - get_dy(); y++) {
                        for (unsigned int x = get_dx(); x < 
                                 search_mask->width() - get_dx(); x++) {
                                if ((*search_mask)(y, x) == 1)
                m_motion_amount = float(motion_pixels) / float(total_pixels);

Spaces, Braces, and Parenthesis

For function and class definitions, it is unambiguous if you put the opening brace on the next line:

void some_function(int param)
        //function body

class SomeClass
        //class body

But for ifs, fors, whiles etc..., there are several possibilities for the braces and parenthesis:


if( some_condition )

if ( some_condition )

if (some_condition)

if (some_condition) {

The preferred way, which is the last, and proposed by K&R, is to put the opening brace last on the line, and put the closing brace first. The reason is to minimize the number of empty lines.

The spaces in math expressions should follow this style:

float a, b, c, d;
int e, f, g, h;

a = (b + d) / (c * d);

e = f - ((g & h) >> 10);    //good
e =f-( (g&h ) >>10);        //bad

Multiple Inclusion Guard

Wrap your header file contents with the multiple inclusion guard to prevent double inclusion:

#ifndef Foo_h
#define Foo_h

// ... Foo.h file contents


Class Layout

When you declare a class, remember that if you do not provide definitions for:

  • constructor
  • copy constructor
  • assignment operator
  • address-of operator (const and non-const)
  • destructor

they will be provided automatically by C++.

//declaring that class
class SomeClass

//you get these functions provided automatically
class SomeClass
        SomeClass() { }                     //constructor
        ~SomeClass() { }                    //destructor
        SomeClass(const SomeClass &rhs);    //copy constructor
        SomeClass& operator=(const SomeClass& rhs); //assignment operator
        SomeClass* operator&();             //address-of
        const SomeClass* operator&() const; //operators;

If you do not intend to provide a copy constructor and an assignment operator, and your class allocates some memory in the constructor and frees it in destructor, declare a copy constructor and an assignment operator as private members to avoid accidental class object cloning and deleting the same memory twice, in the original object and in its copies.

Provide class declarations in the public, protected, and private order. This way, the users of a class will be able to immediately see the public interface they need to use:

#ifndef ClassName_h
#define ClassName_h

class ClassName
    ClassName(const ClassName& classname);
    virtual ~ClassName();

// Operators
    const ClassName& operator=(const ClassName& classname);

// Operations
    int do_work();
    int start_engine();
    int fire_nuke();        

// Access
    inline unsigned int get_users_count() const;        

// Inquiry                
    inline bool is_engine_started() const;

    //protected functions for descendant classes
    //private data and functions
    unsigned int m_users_count;
    bool m_is_engine_started;


// Inlines
inline unsigned int SomeClass::get_users_count() const
    return m_users_count;

inline bool SomeClass::is_engine_started() const
    return m_is_engine_started;

#endif ClassName_h

Keep inlines in header files and outside the class definition, do not garbage the class body.

Const Correctness

Const correctness is to use the keyword const to explicitly declare and prevent the modification of data or objects which should not be modified. Use it at the very outset, as fixing const correctness later will be a nightmare.

You can provide it for data or class member function declarations:

  • const declaration;
  • member-function const;
const int max_array_size = 1024;
max_array_size++;    //compilation error

int a;
int & ra1 = &a;
const int& ra2 = &a;
a = 10;
ra1 = 15;    //ok
ra2 = 20;    //compilation error
//the char data pointed by psour will not be modified
int copy(char* pdest, const char* psour)
   //copy data from psour to pdest

Declaring a member function with the const keyword specifies that the function is a "read-only" function that does not modify the object for which it is called.

class Foo
    void set(int x, int val);
    int get(int x) const;

const Foo* pobj1;        //modification of the pobj1 is forbidden
int i = pobj1->get();    //you can only call const member-functions
                         //with const pointer to class object
pobj1->set(0, 10);       //compilation error

However, declaring a class member variable as mutable allows it to be modified by a const function.

class SomeClass
    void some_function() const;
    mutable int a;

void SomeClass::some_function() const
    a++;    //you can modify a in const function

You can prevent a pointer once assigned to be reassigned to point to another place. This is similar in behaviour to a reference declaration.

Foo foo1, foo2;
int data1[100];
int data2[100];

Foo* const pfoo;
int* const pdata;

pdata = data1;
pfoo = &foo1;

*pdata = 100;        //you can change the data
pfoo->set(0, 10);    //or class object

pdata = data2;       //compilation error
pfoo = &foo2;        //you can not reassign the pointer

You can also declare a const object and a pointer simultaneously:

//neither Foo object can be changed 
//nor pfoo changed to point to another Foo object
const Foo* const pfoo;
const int* const pdata;

Finally, if you provide () or [] operators, provide their const versions also to be used by "read-only" objects.

class SomeClass
    inline int& operator()(int x);      
    inline int operator()(int x) const; 
    inline int& operator[](int x);      
    inline int operator[](int x) const; 

Now, you will be able to use ordinary and const versions of the class object:

SomeClass a;
const SomeClass b;

int i = a(0);
int j = b(0);
a(1) = b(2);
b(3) = a(0);    //compilation error, b object can not be modified

Function Return Value

Functions return values of different types. One of the most typical is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (negative = failure, 0 = success) or a "succeeded" boolean (0 = failure, non-zero = success).

If the name of a function is an action or an imperative command, the function should return an error-code integer. If the name is a predicate, the function should return a "succeeded" boolean.

int start_engine();           //0 = success, negative = error-codes
bool is_engine_started();     //true = success, false = error


Place & or * with a type, not with a variable. This makes it more obvious what the type is.

int& rval;       //&#39;it is&#39; reference int
float* pdata;    //&#39;it is&#39; pointer float

int &rval;
float *pdata;

Define variables that can not have negative values as unsigned (e.g., unsigned int array_length rather than int array_length). This will help to avoid inadvertent assignment to a negative value.

Reference is a const pointer like int* const p, which once assigned, you can not reassign.

int var1 = 100;
int var2 = 200;

int& ref = &var1;
ref = &var2;        //avoid it!

To provide a constant double pointer for Foo** ppfoo, use the declaration const Foo* const* ppfoo.

Always provide formal arguments in function definitions:

void set_point(int, int);       //ambiguous, what are parameters? avoid it, 
void set_point(int x, int y);   //good.

Comparing a pointer against zero:

void some_function(char* pname)
    if (!pname) {
    //error sometimes
    if (pname == NULL) {
    if (pname == 0) {

Pass by reference or pointer, class objects in function parameters. If you pass by value, the whole copy of the class object will be created, which will be bad if it occupies some megabytes of storage.

//avoid it, pass big_object by reference or pointer
BigObject modify_it(BigObject big_object)
    //a local copy of big_object will be created
    return big_object;

//good practice
void modify_it(BigObject& big_object)
    //no copy is created, you can modify the object as usually

OOP Tips

Never return a pointer or non-const reference to private data members of a class. Do not break the encapsulation principle.

class SomeClass
    SomeObject* get_object() { return &m_object; }
    //do not break incapsulation principle
    //m_object can be modified outside the class

    const SomeObject& get_object() { return m_object; }
    //good, the m_object will not be
    //inadvertantly modified outside the class        
    SomeObject* m_object;

Always declare a virtual destructor in a public class. If you derive some class from its parent without a virtual destructor, then if you cast back the derived class object pointer to the parent class and later delete the parent class pointer, only parent destructor will be invoked:

class Base
    ~Base();    //should be virtual ~Base()

class Derived : Base

Derived* pderived = new Derived();
Base* pbase = (Base *)pderived;

delete pbase;    //only ~Base() will be invoked

Use friends. If you do not intend some class to be used by the users of your library, but you access private members of that class from other public classes, providing public accessor methods for it is superfluous. Declare your class as a friend of it, and now you will be able to access its private data.

class MainClass
    void some_function();
    HelperClass* phelper_class;

void some_function()
    int i = phelper_class->m_variable;    //you gain access to private members 
                                          //of HelperClass from MainClass
    phelper_class->m_variable = 10;

class HelperClass
    friend class MainClass;
    int m_variable;


This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


About the Author

Chesnokov Yuriy
Russian Federation Russian Federation
No Biography provided

Comments and Discussions

GeneralMy vote of 1 PinmemberAescleal23-May-10 10:16 
GeneralMy vote of 2 PinmemberJoe Woodbury28-Jun-09 18:12 
QuestionRubik face color detect. Pinmembermerovingi08-Apr-09 22:41 
GeneralEmpty lines in source code PinmemberMa3ztro8-Oct-08 4:54 
Generalconst PinmemberMember 165205130-May-08 5:43 
GeneralWhere to put bulk of #includes, in .h or .cpp :P PinmemberFocusedWolf29-May-08 14:18 
GeneralRe: Where to put bulk of #includes, in .h or .cpp :P PinmemberArman Z. Sahakyan30-May-08 2:55 
GeneralWidth and Height of functions PinmemberArman Z. Sahakyan29-May-08 3:59 
AnswerMiscellaneous PinmemberJKuhn27-May-08 5:29 
GeneralRe: Miscellaneous PinmemberStefan6327-May-08 6:10 
AnswerRe: Miscellaneous PinmemberJKuhn27-May-08 19:12 
GeneralRe: Miscellaneous PinmemberStefan6327-May-08 22:27 
AnswerRe: Miscellaneous PinmvpChesnokov Yuriy27-May-08 19:27 
GeneralOOP and "return" stuff... [modified] Pinmemberrtybase27-May-08 0:01 
GeneralRe: OOP and "return" stuff... PinmemberStefan6327-May-08 0:25 
GeneralRe: OOP and "return" stuff... Pinmemberrtybase27-May-08 0:42 
GeneralRe: OOP and "return" stuff... PinmvpChesnokov Yuriy27-May-08 0:44 
GeneralRe: OOP and "return" stuff... PinmemberSong Gao28-May-08 22:41 
Generalsome additions Pinmemberlfwiertz26-May-08 22:52 
Generalone more addition PinmemberStefan6327-May-08 0:14 
GeneralRe: one more addition PinmemberGer200127-May-08 5:11 
GeneralRe: one more addition PinmemberStefan6327-May-08 5:50 
GeneralUsing reference as class members Pinmembertiousi26-May-08 19:59 
GeneralRe: Using reference as class members PinmemberAnna-Jayne Metcalfe26-May-08 22:22 
GeneralRe: Using reference as class members Pinmemberrtybase27-May-08 23:33 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140821.2 | Last Updated 20 May 2008
Article Copyright 2008 by Chesnokov Yuriy
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid