mirror of
https://github.com/cpp-best-practices/cppbestpractices.git
synced 2025-12-17 11:14:35 +03:00
Merge pull request #12 from axelstudios/master
Small improvements, cleanup
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
|
||||
C++ Best Practices: A Forkable Coding Standards Document
|
||||
|
||||
This document is meant to be a collaborative discussion of the best practices in C++. It complements books such as Effective C++ (Meyers) and C++ Coding Standards (Alexandrescu, Sutter). We fill in some of the lower level details that they don't discuss and provide specific stylistic recommendations while also discussing how to ensure overall code quality.
|
||||
This document is meant to be a collaborative discussion of the best practices in C++. It complements books such as *Effective C++* (Meyers) and *C++ Coding Standards* (Alexandrescu, Sutter). We fill in some of the lower level details that they don't discuss and provide specific stylistic recommendations while also discussing how to ensure overall code quality.
|
||||
|
||||
In all cases brevity and succinctness is prefered. Examples are prefered for making the case for why one option is prefered over another. If necessary, words will be used.
|
||||
In all cases brevity and succinctness is preferred. Examples are preferred for making the case for why one option is preferred over another. If necessary, words will be used.
|
||||
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/Text" property="dct:title" rel="dct:type">C++ Best Practices</span> by <a xmlns:cc="http://creativecommons.org/ns#" href="http://cppbestpractices.com" property="cc:attributionName" rel="cc:attributionURL">Jason Turner</a> is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/">Creative Commons Attribution-NonCommercial 4.0 International License</a>.
|
||||
|
||||
*Disclaimer*
|
||||
|
||||
This document is based on my personal experiences. You are not supposed to agree with it 100%. It exists as a book on [github](https://github.com/lefticus/cppbestpractices) so that you can fork it for your own uses or submit back proposed changes for everyone to share.
|
||||
This document is based on my personal experiences. You are not supposed to agree with it 100%. It exists as a book on [GitHub](https://github.com/lefticus/cppbestpractices) so that you can fork it for your own uses or submit back proposed changes for everyone to share.
|
||||
|
||||
@@ -6,23 +6,23 @@ An automated framework for executing these tools should be established very earl
|
||||
|
||||
Source control is an absolute necessity for any software development project. If you are not using one yet, start using one.
|
||||
|
||||
* [github](http://github.com) - allows for unlimited public repositories, must pay for a private repository
|
||||
* [bitbucket](http://bitbucket.org) - allows for unlimited private repositories with up to 5 collaborators, for free.
|
||||
* [sourceforge](http://sf.net) - open source hosting only
|
||||
* [GitLab](https://gitlab.com/), Subversion, Bitkeeper, many many others... The above are the most popular free services.
|
||||
* [GitHub](https://github.com/) - allows for unlimited public repositories, must pay for a private repository.
|
||||
* [Bitbucket](https://bitbucket.org/) - allows for unlimited private repositories with up to 5 collaborators, for free.
|
||||
* [SourceForge](http://sourceforge.net/) - open source hosting only.
|
||||
* [GitLab](https://gitlab.com/), Subversion, BitKeeper, many many others... The above are the most popular free services.
|
||||
|
||||
## Build Tool
|
||||
|
||||
Use an industry standard widely accepted build tool. This prevents you from reinventing the wheel whenever you discover / link to a new library / package your product / etc. Examples include:
|
||||
|
||||
* [cmake](http://cmake.org)
|
||||
* [biicode](http://biicode.com)
|
||||
* [waf](https://waf.io/)
|
||||
* [CMake](http://www.cmake.org/)
|
||||
* [Biicode](https://www.biicode.com/)
|
||||
* [Waf](https://waf.io/)
|
||||
* [FASTBuild](http://www.fastbuild.org/)
|
||||
* [ninja](https://martine.github.io/ninja/) - can greatly improve the incremental build time of your larger projects. Can be used as a target for cmake
|
||||
* google's build tool
|
||||
* [Ninja](https://martine.github.io/ninja/) - can greatly improve the incremental build time of your larger projects. Can be used as a target for CMake.
|
||||
* [Bazel](http://bazel.io/)
|
||||
|
||||
Remember, it's not just a build tool, it's also a programming language. Try to maintain good clean build scripts and follow the recommended practices for the tool you are using
|
||||
Remember, it's not just a build tool, it's also a programming language. Try to maintain good clean build scripts and follow the recommended practices for the tool you are using.
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
@@ -32,16 +32,17 @@ Continuous Integration (CI) tools automatically build the source code as changes
|
||||
|
||||
* [Travis CI](http://travis-ci.org)
|
||||
* works well with C++
|
||||
* designed for use with github
|
||||
* free for public repositories on github
|
||||
* Hudson CI
|
||||
* Appveyor
|
||||
* designed for use with GitHub
|
||||
* free for public repositories on GitHub
|
||||
* [Hudson CI](http://hudson-ci.org/)
|
||||
* [AppVeyor](http://www.appveyor.com/)
|
||||
* supports Windows and MSVC
|
||||
* [Decent CI](https://github.com/lefticus/decent_ci)
|
||||
* simple ad-hoc continuous integration that posts results to github
|
||||
* supports Windows, MacOS and Linux
|
||||
* simple ad-hoc continuous integration that posts results to GitHub
|
||||
* supports Windows, OS X, and Linux
|
||||
* used by [ChaiScript](http://chaiscript.com/ChaiScript-BuildResults/full_dashboard.html)
|
||||
|
||||
If you have an OpenSource, publicly hosted project on github, go enable travis-ci integration right now. We'll wait for you to come back. For a simple example of how to enable it for your C++ CMake based application, see here: https://github.com/ChaiScript/ChaiScript/blob/master/.travis.yml
|
||||
If you have an open source, publicly-hosted project on GitHub, go enable travis-ci integration right now. We'll wait for you to come back. For a simple example of how to enable it for your C++ CMake-based application, see here: https://github.com/ChaiScript/ChaiScript/blob/master/.travis.yml
|
||||
|
||||
|
||||
## Compilers
|
||||
@@ -80,31 +81,27 @@ Not recommended
|
||||
|
||||
### General
|
||||
|
||||
Start with very strict warnings settings from the beginning. Trying to raise the warning level after the project is underway can be painful.
|
||||
Start with very strict warning settings from the beginning. Trying to raise the warning level after the project is underway can be painful.
|
||||
|
||||
Consider using the "treat warnings as errors" setting. `/Wx` with MSVC, `-Werror` with GCC / Clang
|
||||
Consider using the *treat warnings as errors* setting. `/Wx` with MSVC, `-Werror` with GCC / Clang
|
||||
|
||||
## llvm based tools
|
||||
## LLVM-based tools
|
||||
|
||||
|
||||
include-what-you-use https://github.com/ChaiScript/ChaiScript/commit/c0bf6ee99dac14a19530179874f6c95255fde173
|
||||
|
||||
clang-modernize https://github.com/ChaiScript/ChaiScript/commit/6eab8ddfe154a4ebbe956a5165b390ee700fae1b
|
||||
|
||||
clang-check
|
||||
clang-tidy
|
||||
* [include-what-you-use](https://code.google.com/p/include-what-you-use/), [example results](https://github.com/ChaiScript/ChaiScript/commit/c0bf6ee99dac14a19530179874f6c95255fde173)
|
||||
* [clang-modernize](http://clang.llvm.org/extra/clang-modernize.html), [example results](https://github.com/ChaiScript/ChaiScript/commit/6eab8ddfe154a4ebbe956a5165b390ee700fae1b)
|
||||
* [clang-check](http://clang.llvm.org/docs/ClangCheck.html)
|
||||
* [clang-tidy](http://clang.llvm.org/extra/clang-tidy.html)
|
||||
|
||||
## Static Analyzers
|
||||
|
||||
The best bet is the static analyzer that you can run as part of your automated build system. cppcheck and clang meet that requirement for free options.
|
||||
The best bet is the static analyzer that you can run as part of your automated build system. Cppcheck and clang meet that requirement for free options.
|
||||
|
||||
### cppcheck
|
||||
Cppcheck is free and opensource. It strives for 0 false positives and does a good job at it. Therefore all warnings should be enabled: `-enable=all`
|
||||
### Cppcheck
|
||||
Cppcheck is free and open source. It strives for 0 false positives and does a good job at it. Therefore all warnings should be enabled: `-enable=all`
|
||||
|
||||
### Clang's Static Analyzer
|
||||
|
||||
Clang's analyzer's default options are good for the respective platform. It can be used directly [from cmake](http://garykramlich.blogspot.com/2011/10/using-scan-build-from-clang-with-cmake.html). They can also be called via clang-check and clang-tidy from the LLVM Based Tools.
|
||||
|
||||
Clang's analyzer's default options are good for the respective platform. It can be used directly [from CMake](http://garykramlich.blogspot.com/2011/10/using-scan-build-from-clang-with-cmake.html). They can also be called via clang-check and clang-tidy from the [LLVM-based Tools](#llvm-based-tools).
|
||||
|
||||
### MSVC's Static Analyzer
|
||||
|
||||
@@ -112,7 +109,7 @@ Can be enabled with the `/analyze` [command line option](http://msdn.microsoft.c
|
||||
|
||||
### ReSharper C++ / CLion
|
||||
|
||||
Both of these tools from [JetBrains](https://www.jetbrains.com/cpp/) offer some level of static analysis and automated fixes for common things that can be done better. They have options available for free licenses for Open Source project leaders.
|
||||
Both of these tools from [JetBrains](https://www.jetbrains.com/cpp/) offer some level of static analysis and automated fixes for common things that can be done better. They have options available for free licenses for open source project leaders.
|
||||
|
||||
### Qt Creator
|
||||
|
||||
@@ -130,22 +127,22 @@ While not necessarily a static analyzer, Metrix++ can identify and report on the
|
||||
|
||||
A coverage analysis tool shall be run when tests are executed to make sure the entire application is being tested. Unfortunately, coverage analysis requires that compiler optimizations be disabled. This can result in significantly longer test execution times.
|
||||
|
||||
The most likely candidate for a coverage visualization is the [lcov](http://ltp.sourceforge.net/coverage/lcov.php) project. A secondary option is [coveralls](https://coveralls.io/), which is free for open source projects.
|
||||
The most likely candidate for a coverage visualization is the [LCOV](http://ltp.sourceforge.net/coverage/lcov.php) project. A secondary option is [Coveralls](https://coveralls.io/), which is free for open source projects.
|
||||
|
||||
An alternative to lcov is [gcovr](http://gcovr.com/). It seems to provide similar functionality, but is written in python.
|
||||
<link to chaiscript example of using it>
|
||||
An alternative to LCOV is [Gcovr](http://gcovr.com/). It seems to provide similar functionality, but is written in Python.
|
||||
<link to ChaiScript example of using it>
|
||||
|
||||
### Valgrind
|
||||
|
||||
Runtime code analyzer that can detect memory leaks, race conditions and other associated problems. It is supported on various unix platforms.
|
||||
Runtime code analyzer that can detect memory leaks, race conditions, and other associated problems. It is supported on various Unix platforms.
|
||||
|
||||
### GCC/Clang Sanitizers
|
||||
### GCC / Clang Sanitizers
|
||||
|
||||
These tools provide many of the same features as valgrind, but built into the compiler. They are easy to use and provide a report of what went wrong.
|
||||
These tools provide many of the same features as Valgrind, but built into the compiler. They are easy to use and provide a report of what went wrong.
|
||||
|
||||
* address
|
||||
* thread
|
||||
* undefined
|
||||
* AddressSanitizer
|
||||
* ThreadSanitizer
|
||||
* UndefinedBehaviorSanitizer
|
||||
|
||||
|
||||
## Ignoring Warnings
|
||||
@@ -156,7 +153,7 @@ If it is determined by team consensus that the compiler or analyzer is warning o
|
||||
|
||||
CMake, mentioned above, has a built in framework for executing tests. Make sure whatever build system you use has a way to execute tests built in.
|
||||
|
||||
To further aid in executing tests, consider a library such as [googletest](https://code.google.com/p/googletest/) or [Catch](https://github.com/philsquared/Catch) to help you organize the tests.
|
||||
To further aid in executing tests, consider a library such as [Google Test](https://code.google.com/p/googletest/) or [Catch](https://github.com/philsquared/Catch) to help you organize the tests.
|
||||
|
||||
### Unit Tests
|
||||
|
||||
@@ -164,7 +161,7 @@ Unit tests are for small chunks of code, individual functions which can be teste
|
||||
|
||||
### Integration Tests
|
||||
|
||||
There should be a test enabled for every feature or bug fix that is committed. See also "Code Coverage Analysis." These are tests that are higher level than unit tests. They should still be limited in scope to individual features.
|
||||
There should be a test enabled for every feature or bug fix that is committed. See also [Code Coverage Analysis](#code-coverage-analysis). These are tests that are higher level than unit tests. They should still be limited in scope to individual features.
|
||||
|
||||
### Negative Testing
|
||||
|
||||
|
||||
71
03-Style.md
71
03-Style.md
@@ -1,12 +1,13 @@
|
||||
# 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
|
||||
|
||||
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.
|
||||
are common examples. *snake_case* has the advantage that it can also work with spell checkers, if desired.
|
||||
|
||||
## Common C++ Naming Conventions
|
||||
|
||||
@@ -14,11 +15,11 @@ are common examples. snake_case has the advantage that it can also work with spe
|
||||
* functions and variables start with lower case: `myMethod`
|
||||
* constants are all capital: `const int PI=3.14159265358979323;`
|
||||
|
||||
C++ Standard Library (and other well known C++ libraries like boost) use these guidelines:
|
||||
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 uppercase with underscores: `INT_MAX`
|
||||
* Template parameter names use camel case: `InputIterator`
|
||||
* All other names use snake case: `unordered_map`
|
||||
|
||||
## Distinguish Private Object Data
|
||||
|
||||
@@ -26,13 +27,13 @@ Name private data with a `m_` prefix to distinguish it from public data. `m_` st
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
```
|
||||
```cpp
|
||||
struct Size
|
||||
{
|
||||
int width;
|
||||
@@ -59,14 +60,14 @@ class PrivateSize
|
||||
|
||||
|
||||
|
||||
## Don't name anything starting with an `_`
|
||||
## Don't Name Anything Starting With `_`
|
||||
|
||||
If you do, you risk broaching on names reserved for implementation use
|
||||
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
|
||||
## Well-Formed Example
|
||||
|
||||
```cpp
|
||||
class MyClass
|
||||
@@ -89,11 +90,9 @@ private:
|
||||
|
||||
|
||||
|
||||
## Enable out of source directory builds
|
||||
## Enable Out-of-Source-Directory Builds
|
||||
|
||||
### Make sure generated files go into build folder
|
||||
|
||||
Not the source folder
|
||||
Make sure generated files go into build folder, not the source folder
|
||||
|
||||
|
||||
## Use `nullptr`
|
||||
@@ -124,16 +123,16 @@ int myFunc()
|
||||
|
||||
which would be impossible if the function comment header used `/* */`
|
||||
|
||||
## Never Use `using namespace` In a Header File
|
||||
## 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 own namespace and it may lead to name collisions in the future.
|
||||
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 an distinctly named include guard to avoid problems with including the same header multiple times or conflicting with other headers from other projects
|
||||
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
|
||||
@@ -147,11 +146,11 @@ class MyClass {
|
||||
#endif
|
||||
```
|
||||
|
||||
You may also consider to use the `#pragma once` directive instead which is quasi standard across many compilers.
|
||||
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.
|
||||
## {} Are Required for Blocks.
|
||||
Leaving them off can lead to semantic errors in the code.
|
||||
|
||||
```cpp
|
||||
@@ -178,7 +177,7 @@ for (int i = 0; i < 15; ++i) {
|
||||
}
|
||||
```
|
||||
|
||||
## Keep lines a reasonable length
|
||||
## Keep Lines a Reasonable Length
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
@@ -196,10 +195,10 @@ if (x && y && myFunctionThatReturnsBool()
|
||||
|
||||
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 file next to each other on one screen without having a tiny font.
|
||||
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
|
||||
## Use "" for Including Local Files
|
||||
... `<>` is [reserved for system includes](http://blog2.emptycrate.com/content/when-use-include-verses-include).
|
||||
|
||||
```cpp
|
||||
@@ -257,7 +256,7 @@ private:
|
||||
};
|
||||
```
|
||||
|
||||
In C++11 you may consider to always give each member a default value, e.g. by writing
|
||||
In C++11 you may consider always giving each member a default value, e.g. by writing
|
||||
```cpp
|
||||
// ... //
|
||||
private:
|
||||
@@ -265,16 +264,16 @@ private:
|
||||
// ... //
|
||||
```
|
||||
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 behaviour bugs which are often extremely hard to find.
|
||||
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 namespaces or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other (mostly C, which doesn't have namespaces) libraries.
|
||||
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).
|
||||
|
||||
## Avoid Compiler Macros
|
||||
|
||||
Compiler definitions and macros are replaced by the pre-processor before the compiler is ever run. This can make debugging very difficult because the debugger doesn't know where the source came from.
|
||||
Compiler definitions and macros are replaced by the preprocessor before the compiler is ever run. This can make debugging very difficult because the debugger doesn't know where the source came from.
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
@@ -286,24 +285,24 @@ namespace my_project {
|
||||
public:
|
||||
// if the above macro would be expanded, then the following line would be:
|
||||
// static const double 3.14159 = 3.14159;
|
||||
// which leads to an compile-time error. Sometimes such errors are hard to understand.
|
||||
// which leads to a compile-time error. Sometimes such errors are hard to understand.
|
||||
static const double PI = 3.14159;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Use the correct integer type for stdlib features
|
||||
## 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.
|
||||
|
||||
Make sure you stick with the correct integer types and be 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++ 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
|
||||
## 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, VisualStudio only automatically recognizes .cpp and .cxx for C++ files, plus vim doesn't necessarily recognize .cc as a C++ file.
|
||||
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) 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.
|
||||
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
|
||||
|
||||
@@ -318,9 +317,9 @@ 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
|
||||
## Don't Be Afraid of Templates
|
||||
|
||||
They can help you stick to DRY principles.
|
||||
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
|
||||
## Use Operator Overloads Judiciously
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Considering Safety
|
||||
|
||||
|
||||
## Const as much as possible
|
||||
`const` tells the compiler that a variable or method is immutable. This helps the compiler optimize the code and helps the developer know if a function side effects. Also, using `const &` prevents the compiler from copying data unnecessarily. [Here](http://kotaku.com/454293019) are some comments on const from John Carmack.
|
||||
## Const as Much as Possible
|
||||
`const` tells the compiler that a variable or method is immutable. This helps the compiler optimize the code and helps the developer know if a function has a side effect. Also, using `const &` prevents the compiler from copying data unnecessarily. [Here](http://kotaku.com/454293019) are some comments on `const` from John Carmack.
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
}
|
||||
```
|
||||
|
||||
## Avoid raw memory access
|
||||
## Avoid Raw Memory Access
|
||||
|
||||
Raw memory access, allocation and deallocation, are difficult to get correct in C++ without [risking memory errors and leaks](http://blog2.emptycrate.com/content/nobody-understands-c-part-6-are-you-still-using-pointers). C++11 provides tools to avoid these problems.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Considering Portability
|
||||
|
||||
## Know your types
|
||||
## Know Your Types
|
||||
|
||||
Most portability issues that generate warnings are because we are not careful about our types. standard library and arrays are indexed with size_t. Standard containers sizes are reported in size_t. If you get the handling of size_t wrong, you can create subtle lurking 64bit issues that arise only after you start to overflow the indexing of 32bit integers. char vs unsigned char.
|
||||
Most portability issues that generate warnings are because we are not careful about our types. Standard library and arrays are indexed with `size_t`. Standard container sizes are reported in `size_t`. If you get the handling of `size_t` wrong, you can create subtle lurking 64-bit issues that arise only after you start to overflow the indexing of 32-bit integers. char vs unsigned char.
|
||||
|
||||
http://www.viva64.com/en/a/0010/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Avoid Global Data
|
||||
|
||||
This includes statics and singletons
|
||||
This includes statics and singletons.
|
||||
|
||||
Global data leads to unintended side effects between functions and can make code difficult or impossible to parallelize. Even if the code is not intended today for parallelization, there is no reason to make it impossible for the future.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
|
||||
|
||||
### Forward Declare when Possible
|
||||
### Forward Declare When Possible
|
||||
|
||||
This:
|
||||
|
||||
@@ -31,7 +31,7 @@ This applies to templates as well:
|
||||
template<typename T> class MyTemplatedType;
|
||||
```
|
||||
|
||||
This is a proactive approach to simplify compilation time and rebuilding dependencies.
|
||||
This is a proactive approach to reduce compilation time and rebuilding dependencies.
|
||||
|
||||
### Avoid Unnecessary Template Instantiations
|
||||
|
||||
@@ -39,7 +39,7 @@ Templates are not free to instantiate. Instantiating many templates, or template
|
||||
|
||||
For more examples see [this article](http://blog2.emptycrate.com/content/template-code-bloat-revisited-smaller-makeshared).
|
||||
|
||||
### Firewall Frequently Changing Header Files
|
||||
## Firewall Frequently Changing Header Files
|
||||
|
||||
|
||||
|
||||
@@ -51,23 +51,24 @@ The compiler has to do something with each include directive it sees. Even if it
|
||||
|
||||
### Reduce the load on the preprocessor
|
||||
|
||||
This is a general form of "Firewall Frequently Changing Header Files" and "Don't Unnecessarily Include Headers." Tools like BOOST_PP can be very helpful, but they also put a huge burden on the preprocessor
|
||||
This is a general form of "Firewall Frequently Changing Header Files" and "Don't Unnecessarily Include Headers." Tools like BOOST_PP can be very helpful, but they also put a huge burden on the preprocessor.
|
||||
|
||||
### Consider using precompiled headers
|
||||
|
||||
### Consider Using Tools
|
||||
|
||||
These are not meant to supercede good design
|
||||
These are not meant to supersede good design
|
||||
|
||||
CCACHE, facebook's thing (warp)
|
||||
* [ccache](https://ccache.samba.org/)
|
||||
* [warp](https://github.com/facebook/warp), Facebook's preprocessor
|
||||
|
||||
### Put tmp on Ramdisk
|
||||
|
||||
See [this](https://www.youtube.com/watch?v=t4M3yG1dWho) youtube video for more details.
|
||||
See [this](https://www.youtube.com/watch?v=t4M3yG1dWho) YouTube video for more details.
|
||||
|
||||
### Use the Gold Linker
|
||||
### Use the gold linker
|
||||
|
||||
If on linux, consider using the gold linker for gcc.
|
||||
If on Linux, consider using the gold linker for GCC.
|
||||
|
||||
## Runtime
|
||||
|
||||
@@ -80,12 +81,11 @@ There's no real way to know where your bottlenecks are without analyzing the cod
|
||||
|
||||
### Simplify the Code
|
||||
|
||||
The cleaner, more simple, and easier to read the code is, the better chance the compiler has at implementing it as well.
|
||||
The cleaner, simpler, and easier to read the code is, the better chance the compiler has at implementing it well.
|
||||
|
||||
### Use Initializer Lists
|
||||
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// This
|
||||
std::vector<ModelObject> mos{mo1, mo2};
|
||||
|
||||
@@ -93,18 +93,18 @@ std::vector<ModelObject> mos{mo1, mo2};
|
||||
auto mos = std::vector<ModelObject>{mo1, mo2};
|
||||
```
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Don't do this
|
||||
std::vector<ModelObject> mos;
|
||||
mos.push_back(mo1);
|
||||
mos.push_back(mo2);
|
||||
```
|
||||
|
||||
Initializer lists are significantly more efficient; reducing object copies and resizing of containers
|
||||
Initializer lists are significantly more efficient; reducing object copies and resizing of containers.
|
||||
|
||||
### Reduce Temporary Objects
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Instead of
|
||||
auto mo1 = getSomeModelObject();
|
||||
auto mo2 = getAnotherModelObject();
|
||||
@@ -112,13 +112,13 @@ auto mo2 = getAnotherModelObject();
|
||||
doSomething(mo1, mo2);
|
||||
```
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// consider:
|
||||
|
||||
doSomething(getSomeModelObject(), getAnotherModelObject());
|
||||
```
|
||||
|
||||
This sort of code prevents the compiler from performing a move operation…
|
||||
This sort of code prevents the compiler from performing a move operation...
|
||||
|
||||
### Enable move operations
|
||||
|
||||
@@ -128,21 +128,21 @@ Certain coding choices we make (such as declaring our own destructor or assignme
|
||||
|
||||
For most code, a simple
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
ModelObject(ModelObject &&) = default;
|
||||
```
|
||||
|
||||
would suffice. However, MSVC2013 doesn’t seem to like this code yet.
|
||||
would suffice. However, MSVC2013 doesn't seem to like this code yet.
|
||||
|
||||
### Kill shared_ptr Copies
|
||||
### Kill `shared_ptr` Copies
|
||||
|
||||
shared_ptr objects are much more expensive to copy than you think they should be. This is because the reference count must be atomic and thread safe. So this comment just re-enforces the note above - avoid temporaries and too many copies of objects. Just because we are using a pImpl it does not mean our copies are free.
|
||||
`shared_ptr` objects are much more expensive to copy than you'd think they would be. This is because the reference count must be atomic and thread-safe. So this comment just re-enforces the note above: avoid temporaries and too many copies of objects. Just because we are using a pImpl it does not mean our copies are free.
|
||||
|
||||
### Reduce Copies and Reassignments as Much as Possible
|
||||
|
||||
For more simple cases, the ternary operator can be used
|
||||
For more simple cases, the ternary operator can be used:
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Bad Idea
|
||||
std::string somevalue;
|
||||
|
||||
@@ -153,14 +153,14 @@ if (caseA) {
|
||||
}
|
||||
```
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Better Idea
|
||||
const std::string somevalue = caseA?"Value A":"Value B";
|
||||
```
|
||||
|
||||
More complex cases can be facilited with an [immediately-invoked lambda](http://blog2.emptycrate.com/content/complex-object-initialization-optimization-iife-c11).
|
||||
More complex cases can be facilitated with an [immediately-invoked lambda](http://blog2.emptycrate.com/content/complex-object-initialization-optimization-iife-c11).
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Bad Idea
|
||||
std::string somevalue;
|
||||
|
||||
@@ -173,7 +173,7 @@ if (caseA) {
|
||||
}
|
||||
```
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
// Better Idea
|
||||
const std::string somevalue = [&](){
|
||||
if (caseA) {
|
||||
@@ -194,11 +194,11 @@ Exceptions which are thrown and captured internally during normal processing slo
|
||||
### Get rid of “new”
|
||||
|
||||
We already know that we should not be using raw memory access, so we are using `unique_ptr` and `shared_ptr` instead, right?
|
||||
Heap allocations are much more expensive than stack allocations, but sometimes we have to use them. To make matters worse, creating a shared_ptr actually requires 2 heap allocations.
|
||||
Heap allocations are much more expensive than stack allocations, but sometimes we have to use them. To make matters worse, creating a `shared_ptr` actually requires 2 heap allocations.
|
||||
|
||||
However, the make_shared function reduces this down to just one.
|
||||
However, the `make_shared` function reduces this down to just one.
|
||||
|
||||
```c++
|
||||
```cpp
|
||||
std::shared_ptr<ModelObject_Impl>(new ModelObject_Impl());
|
||||
|
||||
// should become
|
||||
@@ -207,15 +207,15 @@ std::make_shared<ModelObject_Impl>(); // (it's also more readable and concise)
|
||||
|
||||
### Get rid of std::endl
|
||||
|
||||
`std::endl` implies a flush operation. It’s equivalent to `"\n" << std::flush`.
|
||||
`std::endl` implies a flush operation. It's equivalent to `"\n" << std::flush`.
|
||||
|
||||
|
||||
### Limit Variable Scope
|
||||
|
||||
Variables should be declared as late as possible, and ideally, only when it's possible to initialize the object. Reduced variable scope results in less memory being used, more efficient code in general, and helps the compiler optimize the code further.
|
||||
Variables should be declared as late as possible, and ideally only when it's possible to initialize the object. Reduced variable scope results in less memory being used, more efficient code in general, and helps the compiler optimize the code further.
|
||||
|
||||
```c++
|
||||
// Good idea
|
||||
```cpp
|
||||
// Good Idea
|
||||
for (int i = 0; i < 15; ++i)
|
||||
{
|
||||
MyObject obj(i);
|
||||
@@ -232,13 +232,13 @@ for (int i = 0; i < 15; ++i)
|
||||
// obj is still taking up memory for no reason
|
||||
```
|
||||
|
||||
### Prefer double to float
|
||||
### Prefer `double` to `float`
|
||||
|
||||
Operations are doubles are typically faster than float. However, in vectorized operations, float might win out. Analyze the code and find out which is faster for your application!
|
||||
Operations on `double`s are typically faster than `float`s. However, in vectorized operations, `float` might win out. Analyze the code and find out which is faster for your application!
|
||||
|
||||
|
||||
### Prefer ++i to i++
|
||||
... when it is semantically correct. Pre-increment is [faster](http://blog2.emptycrate.com/content/why-i-faster-i-c) then post-increment because it does not require a copy of the object to be made.
|
||||
### Prefer `++i` to `i++`
|
||||
... when it is semantically correct. Pre-increment is [faster](http://blog2.emptycrate.com/content/why-i-faster-i-c) than post-increment because it does not require a copy of the object to be made.
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
The combination of scripting and compiled languages is very powerful. It gives us the things we've come to love about compiled languages: type safety, performance, thread safety options, consistent memory model while also giving us the flexibility to try something new quickly without a full rebuild.
|
||||
|
||||
The VM based compiled languages have learned this already: jruby, jython, ironruby, ironpython
|
||||
The VM based compiled languages have learned this already: JRuby, Jython, IronRuby, IronPython
|
||||
|
||||
* chaiscript
|
||||
* angelscript
|
||||
* luabind
|
||||
* SWIG
|
||||
* ChaiScript
|
||||
* AngelScript
|
||||
* luabind
|
||||
* SWIG
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Further Reading
|
||||
|
||||
* http://geosoft.no/development/cppstyle.html
|
||||
* http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml (Note that google's standard document makes several recommendations which we will NOT be following. For example, they explicitly forbid the use of exceptions, which makes [RAII](http://blog2.emptycrate.com/content/nobody-understands-c-part-2-raii) impossible.)
|
||||
* http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml (Note that Google's standard document makes several recommendations which we will NOT be following. For example, they explicitly forbid the use of exceptions, which makes [RAII](http://blog2.emptycrate.com/content/nobody-understands-c-part-2-raii) impossible.)
|
||||
* http://www.parashift.com/c++-faq/
|
||||
* http://www.cplusplus.com/
|
||||
* http://sourceforge.net/apps/mediawiki/cppcheck/index.php?title=ListOfChecks
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Final Thoughts
|
||||
|
||||
Expand your horizons and use other programming languages. Other languages have different constructs and expressions. Learning what else is out there will encourage you to be more creative with your C++ and write cleaner, more expresive code.
|
||||
Expand your horizons and use other programming languages. Other languages have different constructs and expressions. Learning what else is out there will encourage you to be more creative with your C++ and write cleaner, more expressive code.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user