mirror of
https://github.com/cpp-best-practices/cppbestpractices.git
synced 2025-12-17 19:24:36 +03:00
308 lines
8.8 KiB
Markdown
308 lines
8.8 KiB
Markdown
# Style
|
|
|
|
Consistency of style is more important. Second most importance 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.
|
|
|
|
* `CamelCase`
|
|
* `snake_case`
|
|
|
|
are common examples. *snake_case* has the advantage that it can also work with spell checkers, if desired.
|
|
|
|
## 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;`
|
|
|
|
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`
|
|
|
|
## Distinguish Private Object Data
|
|
|
|
Name private data with a `m_` prefix to distinguish it from public data. `m_` stands for "member" data
|
|
|
|
## Distinguish Function Parameters
|
|
|
|
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.
|
|
|
|
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).
|
|
|
|
```cpp
|
|
struct Size
|
|
{
|
|
int width;
|
|
int height;
|
|
|
|
ValueType(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
|
|
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) {}
|
|
|
|
private:
|
|
int m_width;
|
|
int m_height;
|
|
};
|
|
```
|
|
|
|
|
|
|
|
|
|
## Don't Name Anything Starting With `_`
|
|
|
|
If you do, you risk broaching on names reserved for implementation use:
|
|
|
|
http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier
|
|
|
|
|
|
## Well-Formed Example
|
|
|
|
```cpp
|
|
class MyClass
|
|
{
|
|
public:
|
|
MyClass(int t_data)
|
|
: m_data(t_data)
|
|
{
|
|
}
|
|
|
|
int getData() const
|
|
{
|
|
return m_data;
|
|
}
|
|
|
|
private:
|
|
int m_data;
|
|
};
|
|
```
|
|
|
|
|
|
|
|
## Enable Out-of-Source-Directory Builds
|
|
|
|
Make sure generated files go into build folder, not 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.
|
|
|
|
## Comments
|
|
|
|
Comment blocks should use `//`, not `/* */`. Using `//` makes it much easier to comment out a block of code while debugging.
|
|
|
|
```cpp
|
|
// this function does something
|
|
int myFunc()
|
|
{
|
|
}
|
|
```
|
|
|
|
To comment out this function block during debugging we might do:
|
|
|
|
```cpp
|
|
/*
|
|
// this function does something
|
|
int myFunc()
|
|
{
|
|
}
|
|
*/
|
|
```
|
|
|
|
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.
|
|
Writing `using namespace` in an implementation file is fine though.
|
|
|
|
|
|
## Include Guards
|
|
|
|
Header files must contain a distinctly-named include guard to avoid problems with including the same header multiple times and to prevent conflicts with headers from other projects.
|
|
|
|
```cpp
|
|
#ifndef MYPROJECT_MYCLASS_HPP
|
|
#define MYPROJECT_MYCLASS_HPP
|
|
|
|
namespace MyProject {
|
|
class MyClass {
|
|
};
|
|
}
|
|
|
|
#endif
|
|
```
|
|
|
|
You may also consider using the `#pragma once` directive instead which is quasi-standard across many compilers.
|
|
It's short and makes the intent clear.
|
|
|
|
|
|
## {} Are Required for Blocks.
|
|
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.
|
|
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
|
|
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)
|
|
int sum = 0;
|
|
for (int i = 0; i < 15; ++i) {
|
|
++sum;
|
|
std::cout << i << std::endl;
|
|
}
|
|
```
|
|
|
|
## Keep Lines a Reasonable Length
|
|
|
|
```cpp
|
|
// Bad Idea
|
|
// hard to follow
|
|
if (x && y && myFunctionThatReturnsBool() && caseNumber3 && (15 > 12 || 2 < 3)) {
|
|
}
|
|
|
|
// Good Idea
|
|
// Logical grouping, easier to read
|
|
if (x && y && myFunctionThatReturnsBool()
|
|
&& caseNumber3
|
|
&& (15 > 12 || 2 < 3)) {
|
|
}
|
|
```
|
|
|
|
Many projects and coding standards have a soft guideline that one should try to use less than about 80 or 100 characters per line.
|
|
Such code is generally easier to read.
|
|
It also makes it possible to have two separate files next to each other on one screen without having a tiny font.
|
|
|
|
|
|
## Use "" for Including Local Files
|
|
... `<>` is [reserved for system includes](http://blog2.emptycrate.com/content/when-use-include-verses-include).
|
|
|
|
```cpp
|
|
// Bad Idea. Requires extra -I directives to the compiler
|
|
// 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
|
|
#include <string>
|
|
#include <MyHeader.hpp>
|
|
|
|
|
|
// Good Idea
|
|
// 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
|
|
|
|
```cpp
|
|
// Bad Idea
|
|
class MyClass
|
|
{
|
|
public:
|
|
MyClass(int t_value)
|
|
{
|
|
m_value = t_value;
|
|
}
|
|
|
|
private:
|
|
int m_value;
|
|
};
|
|
|
|
|
|
// 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
|
|
class MyClass
|
|
{
|
|
public:
|
|
MyClass(int t_value)
|
|
: m_value(t_value)
|
|
{
|
|
}
|
|
|
|
private:
|
|
int m_value;
|
|
};
|
|
```
|
|
|
|
In C++11 you may consider always giving each member a default value, e.g. by writing
|
|
```cpp
|
|
// ... //
|
|
private:
|
|
int m_value = 0;
|
|
// ... //
|
|
```
|
|
inside the class body. This makes sure that no constructor ever "forgets" to initialize a member object.
|
|
Forgetting to initialize a member is a source of undefined behavior bugs which are often extremely hard to find.
|
|
|
|
|
|
## 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).
|
|
|
|
|
|
## Use the Correct Integer Type For stdlib Features
|
|
|
|
The standard library generally returns `size_t` for anything related to size. What exactly `size_t` is 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.
|
|
|
|
## Use .hpp and .cpp for Your File Extensions
|
|
|
|
Ultimately this is a matter of preference, but .hpp and .cpp are widely recognized by various editors and tools. So the choice is pragmatic. Specifically, Visual Studio only automatically recognizes .cpp and .cxx for C++ files, and Vim doesn't necessarily recognize .cc as a C++ file.
|
|
|
|
One particularly large project ([OpenStudio](https://github.com/NREL/OpenStudio)) uses .hpp and .cpp for user-generated files and .hxx and .cxx for tool-generated files. Both are well recognized and having the distinction is helpful.
|
|
|
|
## 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.
|
|
|
|
## Never Put Code with Side Effects Inside an assert()
|
|
|
|
```cpp
|
|
assert(registerSomeThing()); // make sure that registerSomeThing() returns true
|
|
```
|
|
|
|
The above code succeeds when making a debug build, but gets removed by the compiler when making a release build, giving you different behavior between debug and release builds.
|
|
This is because `assert()` is a macro which expands to nothing in release mode.
|
|
|
|
## Don't Be Afraid of Templates
|
|
|
|
They can help you stick to [DRY principles](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself).
|
|
They should be preferred to macros, because macros do not honor namespaces, etc.
|
|
|
|
## Use Operator Overloads Judiciously
|