Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 46 additions & 45 deletions 03-Style.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Style

Consistency of style is more important. Second most importance is following a style that the average C++ programmer is used to reading.
Consistency is the most important aspect of style. The second most important aspect is following a style that the average C++ programmer is used to reading.

C++ allows for arbitrary-length identifier names, so there's no reason to be terse when naming variables. Use descriptive names, and be consistent in the style.
C++ allows for arbitrary-length identifier names, so there's no reason to be terse when naming things. Use descriptive names, and be consistent in the style.

* `CamelCase`
* `snake_case`
Expand All @@ -11,27 +11,27 @@ are common examples. *snake_case* has the advantage that it can also work with s

## Common C++ Naming Conventions

* Types start with capitals: `MyClass`
* functions and variables start with lower case: `myMethod`
* constants are all capital: `const double PI=3.14159265358979323;`
* Types start with upper case: `MyClass`.
* Functions and variables start with lower case: `myMethod`.
* Constants are all upper case: `const double PI=3.14159265358979323;`.

C++ Standard Library (and other well-known C++ libraries like [Boost](http://www.boost.org/)) use these guidelines:

* Macro names use uppercase with underscores: `INT_MAX`
* Template parameter names use camel case: `InputIterator`
* All other names use snake case: `unordered_map`
* Macro names use upper case with underscores: `INT_MAX`.
* Template parameter names use camel case: `InputIterator`.
* All other names use snake case: `unordered_map`.

## Distinguish Private Object Data

Name private data with a `m_` prefix to distinguish it from public data. `m_` stands for "member" data
Name private data with a `m_` prefix to distinguish it from public data. `m_` stands for "member" data.

## Distinguish Function Parameters

The most important thing is consistency within your codebase, this is one possibility to help with consistency.
The most important thing is consistency within your codebase; this is one possibility to help with consistency.

Name function parameters with an `t_` prefix. `t_` can be thought of as "the", but the meaning is arbitrary. The point is to distinguish function parameters from other variables in scope while giving us a consistent naming strategy.

By using `t_` for parameters and `m_` for module data, we can have consistency with both public members of structs and private members of classes.
By using `t_` for parameters and `m_` for member data, we can have consistency with both public members of structs and private members of classes.

Any prefix or postfix can be chosen for your organization. This is just one example. *This suggestion is controversial, for a discussion about it see issue [#11](https://github.com/lefticus/cppbestpractices/issues/11).*

Expand All @@ -41,17 +41,17 @@ struct Size
int width;
int height;

ValueType(int t_width, int t_height) : width(t_width), height(t_height) {}
Size(int t_width, int t_height) : width(t_width), height(t_height) {}
};

// this version might make sense for thread safety or something,
// but more to the point, sometimes we need to hide data, sometimes we don't
// This version might make sense for thread safety or something,
// but more to the point, sometimes we need to hide data, sometimes we don't.
class PrivateSize
{
public:
int width() const { return m_width; }
int height() const { return m_height; }
ValueType(int t_width, int t_height) : m_width(t_width), m_height(t_height) {}
PrivateSize(int t_width, int t_height) : m_width(t_width), m_height(t_height) {}

private:
int m_width;
Expand All @@ -64,7 +64,7 @@ class PrivateSize

## Don't Name Anything Starting With `_`

If you do, you risk broaching on names reserved for implementation use:
If you do, you risk colliding with names reserved for compiler and standard library implementation use:

http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier

Expand Down Expand Up @@ -94,12 +94,12 @@ private:

## Enable Out-of-Source-Directory Builds

Make sure generated files go into build folder, not the source folder
Make sure generated files go into an output folder that is separate from the source folder.


## Use `nullptr`

C++11 introduces `nullptr` which is a special type denoting a null pointer value. This should be used instead of `0` or `NULL` to indicate a null pointer.
C++11 introduces `nullptr` which is a special value denoting a null pointer. This should be used instead of `0` or `NULL` to indicate a null pointer.

## Comments

Expand All @@ -123,12 +123,12 @@ int myFunc()
*/
```

which would be impossible if the function comment header used `/* */`
which would be impossible if the function comment header used `/* */`.

## Never Use `using namespace` in a Header File

This causes the name space you are `using` to be pulled into the namespace of the header file.
It litters the namespace and it may lead to name collisions in the future.
This causes the namespace you are `using` to be pulled into the namespace of all files that include the header file.
It pollutes the namespace and it may lead to name collisions in the future.
Writing `using namespace` in an implementation file is fine though.


Expand Down Expand Up @@ -157,21 +157,22 @@ Leaving them off can lead to semantic errors in the code.

```cpp
// Bad Idea
// this compiles and does what you want, but can lead to confusing
// errors if close attention is not paid.
// This compiles and does what you want, but can lead to confusing
// errors if modification are made in the future and close attention
// is not paid.
for (int i = 0; i < 15; ++i)
std::cout << i << std::endl;

// Bad Idea
// the cout is not part of the loop in this case even though it appears to be
// The cout is not part of the loop in this case even though it appears to be.
int sum = 0;
for (int i = 0; i < 15; ++i)
++sum;
std::cout << i << std::endl;


// Good Idea
// It's clear which statements are part of the loop (or if block, or whatever)
// It's clear which statements are part of the loop (or if block, or whatever).
int sum = 0;
for (int i = 0; i < 15; ++i) {
++sum;
Expand Down Expand Up @@ -205,26 +206,26 @@ It also makes it possible to have two separate files next to each other on one s

```cpp
// Bad Idea. Requires extra -I directives to the compiler
// and goes against standards
// and goes against standards.
#include <string>
#include <includes/MyHeader.hpp>

// Worse Idea
// requires potentially even more specific -I directives and
// makes code more difficult to package and distribute
// Requires potentially even more specific -I directives and
// makes code more difficult to package and distribute.
#include <string>
#include <MyHeader.hpp>


// Good Idea
// requires no extra params and notifies the user that the file
// is a local file
// Requires no extra params and notifies the user that the file
// is a local file.
#include <string>
#include "MyHeader.hpp"
```

## Initialize Member Variables
...with the member initializer list
...with the member initializer list.

```cpp
// Bad Idea
Expand All @@ -244,7 +245,7 @@ private:
// Good Idea
// C++'s member initializer list is unique to the language and leads to
// cleaner code and potential performance gains that other languages cannot
// match
// match.
class MyClass
{
public:
Expand All @@ -267,7 +268,7 @@ private:
```
inside the class body. This makes sure that no constructor ever "forgets" to initialize a member object.

Use brace initialization, it does not allow narrowing at compile-time:
Use brace initialization; it does not allow narrowing at compile-time:
```cpp
// Best Idea

Expand All @@ -283,16 +284,16 @@ Forgetting to initialize a member is a source of undefined behavior bugs which a

## Always Use Namespaces

There is almost never a reason to declare an identifier in the global namespaces. Instead, functions and classes should exist in an appropriately named namespace or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other libraries (mostly C, which doesn't have namespaces).
There is almost never a reason to declare an identifier in the global namespace. Instead, functions and classes should exist in an appropriately named namespace or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other libraries (mostly C, which doesn't have namespaces).


## Use the Correct Integer Type For stdlib Features
## Use the Correct Integer Type for Standard Library Features

The standard library generally returns `size_t` for anything related to size. What exactly `size_t` is, is implementation defined.
The standard library generally uses `std::size_t` for anything related to size. The size of `size_t` is implementation defined.

In general, using `auto` will avoid most of these issues, but not all.

Make sure you stick with the correct integer types and remain consistent with the C++ stdlib. It might not warn on the platform you are currently using, but it probably will when you change platforms.
Make sure you stick with the correct integer types and remain consistent with the C++ standard library. It might not warn on the platform you are currently using, but it probably will when you change platforms.

## Use .hpp and .cpp for Your File Extensions

Expand All @@ -302,7 +303,7 @@ One particularly large project ([OpenStudio](https://github.com/NREL/OpenStudio)

## Never Mix Tabs and Spaces

Some editors like to indent with a mixture of tabs and spaces by default. This makes the code unreadable to anyone not using the exact same tab indentation settings.
Some editors like to indent with a mixture of tabs and spaces by default. This makes the code unreadable to anyone not using the exact same tab indentation settings. Configure your editor so this does not happen.

## Never Put Code with Side Effects Inside an assert()

Expand All @@ -322,17 +323,17 @@ They should be preferred to macros, because macros do not honor namespaces, etc.

Operator overloading was invented to enable expressive syntax. Expressive in the sense that adding two big integers looks like `a + b` and not `a.add(b)`. Another common example is std::string, where it is very common to concatenate two strings with `string1 + string2`.

However, you can easily create unreadable expressions using too much or wrong operator overloading. When overloading operators, there are three basic rules to follow as described [on stackoverflow](http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708)
However, you can easily create unreadable expressions using too much or wrong operator overloading. When overloading operators, there are three basic rules to follow as described [on stackoverflow](http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708).

More detailed, you should keep these things in mind:
Specifically, you should keep these things in mind:

* Overloading `operator=` when handling with resources is a must, see [Consider the Rule of Zero](03-Style.md#consider-the-rule-of-zero) below.
* Overloading `operator=()` when handling resources is a must. See [Consider the Rule of Zero](03-Style.md#consider-the-rule-of-zero) below.
* For all other operators, only overload them when they are used in a context that is commonly connected to these operators. Typical scenarios are concatenating things with +, negating expressions that can be considered "true" or "false", etc.
* Always be aware of the [operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence) and try to circumvent unintuitive constructs.
* Always be aware of the [operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence) and try to circumvent unintuitive constructs.
* Do not overload exotic operators such as ~ or % unless implementing a numeric type or following a well recognized syntax in specific domain.
* [Never](http://stackoverflow.com/questions/5602112/when-to-overload-the-comma-operator?answertab=votes#tab-top) overload `operator ,` (the comma operator).
* Use `operator >>` and `operator <<` when dealing with streams. For example, you can overload `operator <<(std::ostream &, MyClass const &)` to enable "writing" you class into a stream, such as std::cout or an std::fstream or std::stringstream. The latter is often used to create a textual representation of a value.
* There are more common operators to overload [described here](http://stackoverflow.com/questions/4421706/operator-overloading?answertab=votes#tab-top)
* [Never](http://stackoverflow.com/questions/5602112/when-to-overload-the-comma-operator?answertab=votes#tab-top) overload `operator,()` (the comma operator).
* Use non-member functions `operator>>()` and `operator<<()` when dealing with streams. For example, you can overload `operator<<(std::ostream &, MyClass const &)` to enable "writing" your class into a stream, such as `std::cout` or an `std::fstream` or `std::stringstream`. The latter is often used to create a string representation of a value.
* There are more common operators to overload [described here](http://stackoverflow.com/questions/4421706/operator-overloading?answertab=votes#tab-top).

More tips regarding the implementation details of your custom operators can be found [here](http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html).

Expand Down