diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..c7270da --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: lefticus +patreon: lefticus diff --git a/00-Table_of_Contents.md b/00-Table_of_Contents.md index 2246a46..7f2b1a3 100644 --- a/00-Table_of_Contents.md +++ b/00-Table_of_Contents.md @@ -7,8 +7,7 @@ 6. [Considering Portability](06-Considering_Portability.md) 7. [Considering Threadability](07-Considering_Threadability.md) 8. [Considering Performance](08-Considering_Performance.md) - 9. [Enable Scripting](09-Enable_Scripting.md) - 10. [Further Reading](10-Further_Reading.md) - 11. [Final Thoughts](11-Final_Thoughts.md) - - + 9. [Considering Correctness](09-Considering_Correctness.md) + 10. [Enable Scripting](10-Enable_Scripting.md) + 11. [Further Reading](11-Further_Reading.md) + 12. [Final Thoughts](12-Final_Thoughts.md) diff --git a/02-Use_the_Tools_Available.md b/02-Use_the_Tools_Available.md index 90a43f8..83e8cb8 100644 --- a/02-Use_the_Tools_Available.md +++ b/02-Use_the_Tools_Available.md @@ -6,31 +6,52 @@ 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](https://github.com/) - allows for unlimited public repositories, must pay for a private repository. + * [GitHub](https://github.com/) - allows for unlimited public repositories, and unlimited private repositories with up to 3 collaborators. * [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. + * [GitLab](https://gitlab.com/) - allows for unlimited public and private repositories, unlimited CI Runners included, for free. * [Visual Studio Online](https://visualstudio.com) (http://www.visualstudio.com/what-is-visual-studio-online-vs) - allows for unlimited public repositories, must pay for private repository. Repositories can be git or TFVC. Additionally: Issue tracking, project planning (multiple Agile templates, such as SCRUM), integrated hosted builds, integration of all this into Microsoft Visual Studio. Windows only. ## 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: + * [Autotools](https://autotools.io) - The traditional GNU build system. * [CMake](http://www.cmake.org/) * Consider: https://github.com/sakra/cotire/ for build performance * Consider: https://github.com/toeb/cmakepp for enhanced usability - * [Conan](https://www.conan.io/) - a crossplatform dependency manager for C++ + * Utilize: https://cmake.org/cmake/help/v3.6/command/target_compile_features.html for C++ standard flags + * Consider: https://github.com/cheshirekow/cmake_format for automatic formatting of your CMakeLists.txt + * See the [Further Reading](11-Further_Reading.md) section for CMake specific best practices + * `cmake --build` provides a common interface for compiling your project regardless of platform * [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. - * [Bazel](http://bazel.io/) - Note: MacOS and Linux only. + * [Ninja](https://ninja-build.org/) - Can greatly improve the incremental build time of your larger projects. Can be used as a target for CMake. + * [Bazel](http://bazel.io/) - Fast incremental builds using network artifact caching and remote execution. + * [Buck](http://buckbuild.com/) - Similar to Bazel, with very good support for iOS and Android. * [gyp](https://chromium.googlesource.com/external/gyp/) - Google's build tool for chromium. * [maiken](https://github.com/Dekken/maiken) - Crossplatform build tool with Maven-esque configuration style. * [Qt Build Suite](http://doc.qt.io/qbs/) - Crossplatform build tool From Qt. - * [meson](http://mesonbuild.com/index.html) - Open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. + * [meson](http://mesonbuild.com/index.html) - Open source build system meant to be both extremely fast, and, even more importantly, as user-friendly as possible. + * [premake](https://premake.github.io/) + * [xmake](https://xmake.io) - A cross-platform build utility based on Lua. Modern C/C++ build tools, Support multi-language hybrid compilation + * [build2](https://build2.org) - A cargo-like complete toolchain (build system, package manager, project manager) 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. +## Package Manager + +Package management is an important topic in C++, with currently no clear winner. Consider using a package manager to help you keep track of the dependencies for your project and make it easier for new people to get started with the project. + + * [Conan](https://www.conan.io/) - a crossplatform dependency manager for C++ + * [hunter](https://github.com/ruslo/hunter) - CMake driven cross-platform package manager for C/C++ + * [C++ Archive Network (CPPAN)](https://cppan.org/) - a crossplatform dependency manager for C++ + * [qpm](https://www.qpm.io/) - Package manager for Qt + * [build2](https://build2.org/) - A cargo-like complete toolchain (build system, package manager, project manager) + * [Buckaroo](https://buckaroo.pm) - Truly decentralized cross-platform dependency manager for C/C++ and more + * [Vcpkg](https://github.com/microsoft/vcpkg) - Microsoft C++ Library Manager for Windows, Linux, and macOS - [description](https://docs.microsoft.com/en-us/cpp/build/vcpkg) + * [CPM](https://github.com/cpm-cmake/CPM.cmake) - CMake package manager for modern CMake + ## Continuous Integration Once you have picked your build tool, set up a continuous integration environment. @@ -48,7 +69,7 @@ Continuous Integration (CI) tools automatically build the source code as changes * Java Application Server is required * supports Windows, OS X, and Linux * extendable with a lot of plugins - * [TeamCity](https://www.jetbrains.com/teamcity) + * [TeamCity](https://www.jetbrains.com/teamcity) * has a free option for open source projects * [Decent CI](https://github.com/lefticus/decent_ci) * simple ad-hoc continuous integration that posts results to GitHub @@ -60,26 +81,31 @@ Continuous Integration (CI) tools automatically build the source code as changes * Provides hosted build agents and also allows for user-provided build agents * Can be controlled and monitored from within Microsoft Visual Studio * On-Premise installation via Microsoft Team Foundation Server + * [GitLab](https://gitlab.com) + * use custom Docker images, so can be used for C++ + * has free shared runners + * has trivial processing of result of coverage analyze If you have an open source, publicly-hosted project on GitHub: - * go enable Travis Ci and AppVeyor 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 + * go enable github actions. A template for this can be found in the [C++ Boilerplate Template](https://github.com/cpp-best-practices/cmake_conan_boilerplate_template) * enable one of the coverage tools listed below (Codecov or Coveralls) * enable [Coverity Scan](https://scan.coverity.com) - + These tools are all free and relatively easy to set up. Once they are set up you are getting continuous building, testing, analysis and reporting of your project. For free. ## Compilers -Use every available and reasonable set of warning options +Use every available and reasonable set of warning options. Some warning options only work with optimizations enabled, or work better the higher the chosen level of optimization is, for example [`-Wnull-dereference`](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wnull-dereference-367) with GCC. You should use as many compilers as you can for your platform(s). Each compiler implements the standard slightly differently and supporting multiple will help ensure the most portable, most reliable code. ### GCC / Clang -`-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic` +`-Wall -Wextra -Wshadow -Wnon-virtual-dtor -pedantic` - use these and consider the following (see descriptions below) + * `-pedantic` - Warn on language extensions * `-Wall -Wextra` reasonable and standard * `-Wshadow` warn the user if a variable declaration shadows one from a parent context * `-Wnon-virtual-dtor` warn the user if a class with virtual functions has a non-virtual destructor. This helps catch hard to track down memory errors @@ -87,10 +113,19 @@ You should use as many compilers as you can for your platform(s). Each compiler * `-Wcast-align` warn for potential performance problem casts * `-Wunused` warn on anything being unused * `-Woverloaded-virtual` warn if you overload (not override) a virtual function - * `-pedantic` + * `-Wpedantic` (all versions of GCC, Clang >= 3.2) warn if non-standard C++ is used * `-Wconversion` warn on type conversions that may lose data - * `-Wsign-conversion` warn on sign conversions - * `-Wmisleading-indentation` warn if identation implies blocks where blocks do not exist + * `-Wsign-conversion` (Clang all versions, GCC >= 4.3) warn on sign conversions + * `-Wmisleading-indentation` (only in GCC >= 6.0) warn if indentation implies blocks where blocks do not exist + * `-Wduplicated-cond` (only in GCC >= 6.0) warn if `if` / `else` chain has duplicated conditions + * `-Wduplicated-branches` (only in GCC >= 7.0) warn if `if` / `else` branches have duplicated code + * `-Wlogical-op` (only in GCC) warn about logical operations being used where bitwise were probably wanted + * `-Wnull-dereference` (only in GCC >= 6.0) warn if a null dereference is detected + * `-Wuseless-cast` (only in GCC >= 4.8) warn if you perform a cast to the same type + * `-Wdouble-promotion` (GCC >= 4.6, Clang >= 3.8) warn if `float` is implicitly promoted to `double` + * `-Wformat=2` warn on security issues around functions that format output (i.e., `printf`) + * `-Wlifetime` (only special branch of Clang currently) shows object lifetime issues + * `-Wimplicit-fallthrough` Warns when case statements fall-through. (Included with `-Wextra` in GCC, not in clang) Consider using `-Weverything` and disabling the few warnings you need to on Clang @@ -99,7 +134,9 @@ Consider using `-Weverything` and disabling the few warnings you need to on Clan ### MSVC -`/W4 /W44640` - use these and consider the following +`/permissive-` - [Enforces standards conformance](https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance). + +`/W4 /w14640` - use these and consider the following (see descriptions below) * `/W4` All reasonable warnings * `/w14242` 'identfier': conversion from 'type1' to 'type1', possible loss of data @@ -116,7 +153,7 @@ Consider using `-Weverything` and disabling the few warnings you need to on Clan * `/w14549` 'operator': operator before comma has no effect; did you intend 'operator'? * `/w14555` expression has no effect; expected expression with side-effect * `/w14619` pragma warning: there is no warning number 'number' - * `/w14640` Enable warning on thread un-safe static member initialization + * `/w14640` Enable warning on thread unsafe static member initialization * `/w14826` Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. * `/w14905` wide string literal cast to 'LPSTR' * `/w14906` string literal cast to 'LPWSTR' @@ -124,7 +161,8 @@ Consider using `-Weverything` and disabling the few warnings you need to on Clan Not recommended - * `/Wall` - Also warns on files included from the standard library, so it's not very useful and creates too many extra warnings. + * `/Wall` - Not recommended for normal builds because the MSVC standard library is not `/Wall` "clean", but can be enabled to discover new warnings to enable. + * Since VS2022, `/external:anglebrackets /external:W0` can be used to turn off warnings from all headers included with angle brackets, e.g. `#include `. @@ -132,12 +170,21 @@ Not recommended 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 work best with a build system (such as cmake) that can output a compile command database, for example: + +``` +$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON . +``` + +If you are not using a build system like that, you can consider [Build EAR](https://github.com/rizsotto/Bear) which will hook into your build system and generate a compile command database for you. + +CMake now also comes with built-in support for calling `clang-tidy` during [normal compilation](https://cmake.org/cmake/help/latest/prop_tgt/LANG_CLANG_TIDY.html). + * [include-what-you-use](https://github.com/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) @@ -145,17 +192,46 @@ Consider using the *treat warnings as errors* setting. `/Wx` with MSVC, `-Werror 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. -### Coverity Scan +### SonarLint / SonarQube / SonarCloud + +[SonarLint](https://www.sonarsource.com/products/sonarlint/) runs as a plug-in in all the main IDEs. The other two run as part of your build pipeline and can also gate PRs. [SonarQube](https://www.sonarsource.com/products/sonarqube/) runs on your own infrastructure whereas [SonarCloud](https://www.sonarsource.com/products/sonarcloud/) runs in The Cloud, is free for public Open Source projects and supports Automatic Analysis for zero-config setup. + +All three run the same set of analyzers (although SonarQube and SonarCloud have a handful of additional checks that are too heavyweight to run in-IDE) that catch code smells and best practice violations, as well as complex bugs. + +### Coverity Scan [Coverity](https://scan.coverity.com/) has a free (for open source) static analysis toolkit that can work on every commit in integration with [Travis CI](http://travis-ci.org) and [AppVeyor](http://www.appveyor.com/). +### PVS-Studio + +[PVS-Studio](http://www.viva64.com/en/pvs-studio/) is a tool for bug detection in the source code of programs, written in C, C++ and C#. It is free for personal academic projects, open source non-commercial projects and independent projects of individual developers. It works in Windows and Linux environment. + ### Cppcheck [Cppcheck](http://cppcheck.sourceforge.net/) 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` +Notes: + + * For correct work it requires well formed path for headers, so before usage don't forget to pass: `--check-config`. + * Finding unused headers does not work with `-j` more than 1. + * Remember to add `--force` for code with a lot number of `#ifdef` if you need to check all of them. + +### cppclean + +[cppclean](https://github.com/myint/cppclean) - Open source static analyzer focused on finding problems in C++ source that slow development of large code bases. + + +### CppDepend + +[CppDepend](https://www.cppdepend.com/) Simplifies managing a complex C/C++ code base by analyzing and visualizing code dependencies, by defining design rules, by doing impact analysis, and comparing different versions of the code. It's free for OSS contributors. + ### 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](#llvm-based-tools). +Also, [CodeChecker](https://github.com/Ericsson/CodeChecker) is available as a front-end to clang's static analysis. + +`clang-tidy` can be easily used with Visual Studio via the [Clang Power Tools](https://clangpowertools.com) extension. + ### MSVC's Static Analyzer Can be enabled with the `/analyze` [command line option](http://msdn.microsoft.com/en-us/library/ms173498.aspx). For now we will stick with the default options. @@ -164,17 +240,34 @@ Can be enabled with the `/analyze` [command line option](http://msdn.microsoft.c [Flint](https://github.com/facebook/flint) and [Flint++](https://github.com/L2Program/FlintPlusPlus) are linters that analyze C++ code against Facebook's coding standards. +### OCLint + +[OCLint](http://oclint.org/) is a free, libre and open source static code analysis tool for improving quality of C++ code in many different ways. + ### 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. -### Cevelop +### Cevelop The Eclipse based [Cevelop](https://www.cevelop.com/) IDE has various static analysis and refactoring / code fix tools available. For example, you can replace macros with C++ `constexprs`, refactor namespaces (extract/inline `using`, qualify name), and refactor your code to C++11's uniform initialization syntax. Cevelop is free to use. ### Qt Creator -Qt Creator can plug into the clang static analyzer, but *only* on the *commercial* version of Qt Creator. +Qt Creator can plug into the clang static analyzer. + +### clazy + +[clazy](https://github.com/KDE/clazy) is a clang based tool for analyzing Qt usage. + +### IKOS + +[IKOS](https://ti.arc.nasa.gov/opensource/ikos/) is an open source static analyzer, developed by NASA. It is based on the Abstract Interpretation. It is written in C++ and provides an analyzer for C and C++, using LLVM. +The source code is [available on GitHub](https://github.com/NASA-SW-VnV/ikos). + +### codespell + +[codespell](https://github.com/codespell-project/codespell) is a spell checker for your source code. ## Runtime Checkers @@ -189,29 +282,47 @@ A coverage analysis tool shall be run when tests are executed to make sure the e * integrates with Travis CI and AppVeyor * free for open source projects * [LCOV](http://ltp.sourceforge.net/coverage/lcov.php) - * very configurable + * very configurable * [Gcovr](http://gcovr.com/) + * [kcov](http://simonkagstrom.github.io/kcov/index.html) + * integrates with codecov and coveralls + * performs code coverage reporting without needing special compiler flags, just by instrumenting debug symbols. + * [OpenCppCoverage](https://github.com/OpenCppCoverage/OpenCppCoverage) - open source coverage reporting tool for Windows. + +### Heap profiling -### Valgrind + * [Valgrind](http://www.valgrind.org/) + * Valgrind is a runtime code analyzer that can detect memory leaks, race conditions, and other associated problems. It is supported on various Unix platforms. + * [Heaptrack](https://github.com/KDE/heaptrack) + * A profiler created by a Valgrind's Massif developer. Quite similar to Massif with pros and cons over it, way more intuitive though. + * [Dr Memory](http://www.drmemory.org) + * [Memoro](https://epfl-vlsc.github.io/memoro/) - A detailed heap profiler. -[Valgrind](http://www.valgrind.org/) is a runtime code analyzer that can detect memory leaks, race conditions, and other associated problems. It is supported on various Unix platforms. +### CPU profiling -### Dr Memory + * [Hotspot](https://github.com/KDAB/hotspot) - An intuitive front-end to visualize datas produced by the [perf](https://perf.wiki.kernel.org) CPU profiler. + * [uftrace](https://github.com/namhyung/uftrace) - Can be used to generating function call graphs of a program execution. -Similar to Valgrind. http://www.drmemory.org +### Reverse engineering tools + + * [Cutter](https://cutter.re/) - A front-end for [Radare2](https://www.radare.org/n/radare2.html). It provides tools such as decompiler, disassembly, graph visualizer, hex editor. + * [Ghidra](https://ghidra-sre.org/) - Ghidra is a free and open source reverse engineering tool developed by the National Security Agency (NSA) of the United States. ### 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. * AddressSanitizer + * MemorySanitizer * ThreadSanitizer * UndefinedBehaviorSanitizer +Be aware of the sanitizer options available, including runtime options. https://kristerw.blogspot.com/2018/06/useful-gcc-address-sanitizer-checks-not.html + ### Fuzzy Analyzers -If your project accepts user defined input, considering running a fuzzy input tester. +If your project accepts user defined input, considering running a fuzzy input tester. Both of these tools use coverage reporting to find new code execution paths and try to breed novel inputs for your code. They can find crashes, hangs, and inputs you didn't know were considered valid. @@ -219,15 +330,41 @@ Both of these tools use coverage reporting to find new code execution paths and * [LibFuzzer](http://llvm.org/docs/LibFuzzer.html) * [KLEE](http://klee.github.io/) - Can be used to fuzz individual functions +#### Continuous Fuzzing + +Continuous fuzzing tools exist to run fuzz tests for you with each commit. + + * [Fuzzit](https://fuzzit.dev/) + +### Mutation Testers + +These tools take code executed during unit test runs and mutate the executed code. If the test continues to pass with a mutation in place, then there is likely a flawed test in your suite. + + * [Dextool Mutate](https://github.com/joakim-brannstrom/dextool/tree/master/plugin/mutate) + * [MuCPP](https://neptuno.uca.es/redmine/projects/mucpp-mutation-tool/wiki) + * [mull](https://github.com/mull-project/mull) + * [CCMutator](https://github.com/markus-kusano/CCMutator) + * [Universal Mutator](https://github.com/agroce/universalmutator) + +### Control Flow Guard + +MSVC's [Control Flow Guard](https://msdn.microsoft.com/en-us/library/windows/desktop/mt637065%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396) adds high performance runtime security checks. + +### Checked STL Implementations + + * `_GLIBCXX_DEBUG` with GCC's implementation libstdc++ implementation. See [Krister's blog article](https://kristerw.blogspot.se/2018/03/detecting-incorrect-c-stl-usage.html). + ## Ignoring Warnings If it is determined by team consensus that the compiler or analyzer is warning on something that is either incorrect or unavoidable, the team will disable the specific error to as localized part of the code as possible. +Be sure to reenable the warning after disabling it for a section of code. You do not want your disabled warnings to [leak into other code](http://www.forwardscattering.org/post/48). + ## Testing -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. +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 [Google Test](https://code.google.com/p/googletest/), [Catch](https://github.com/philsquared/Catch) or [Boost.Test](http://www.boost.org/doc/libs/release/libs/test/) to help you organize the tests. +To further aid in executing tests, consider a library such as [Google Test](https://github.com/google/googletest), [Catch](https://github.com/philsquared/Catch), [CppUTest](https://github.com/cpputest/cpputest) or [Boost.Test](http://www.boost.org/doc/libs/release/libs/test/) to help you organize the tests. ### Unit Tests @@ -241,8 +378,28 @@ There should be a test enabled for every feature or bug fix that is committed. S Don't forget to make sure that your error handling is being tested and works properly as well. This will become obvious if you aim for 100% code coverage. +## Debugging + +### GDB + +[GDB](https://www.gnu.org/software/gdb/) - The GNU debugger, powerful and widely used. Most IDEs implement an interface to use it. + +### rr + +[rr](http://rr-project.org/) is a free (open source) reverse debugger that supports C++. + + +## Documentation Tools + + * [hdoc](https://hdoc.io/) the modern documentation tool for C++ + + ## Other Tools +### Lizard + +[Lizard](http://www.lizard.ws/) provides a very simple interface for running complexity analysis against a C++ codebase. + ### Metrix++ [Metrix++](http://metrixplusplus.sourceforge.net/) can identify and report on the most complex sections of your code. Reducing complex code helps you and the compiler understand it better and optimize it better. @@ -251,14 +408,26 @@ Don't forget to make sure that your error handling is being tested and works pro [ABI Compliance Checker](http://ispras.linuxbase.org/index.php/ABI_compliance_checker) (ACC) can analyze two library versions and generates a detailed compatibility report regarding API and C++ ABI changes. This can help a library developer spot unintentional breaking changes to ensure backward compatibility. -### CNCC +### CNCC [Customizable Naming Convention Checker](https://github.com/mapbox/cncc) can report on identifiers in your code that do not follow certain naming conventions. ### ClangFormat -[ClangFormat](http://clang.llvm.org/docs/ClangFormat.html) can check and correct code formatting to match organizational conventions automatically. +[ClangFormat](http://clang.llvm.org/docs/ClangFormat.html) can check and correct code formatting to match organizational conventions automatically. [Multipart series](https://engineering.mongodb.com/post/succeeding-with-clangformat-part-1-pitfalls-and-planning/) on utilizing clang-format. -### SourceMeter +### SourceMeter [SourceMeter](https://www.sourcemeter.com/) offers a free version which provides many different metrics for your code and can also call into cppcheck. + +### Bloaty McBloatface + +[Bloaty McBloatface](https://github.com/google/bloaty) is a binary size analyzer/profiler for unix-like platforms + +### pahole + +[pahole](https://linux.die.net/man/1/pahole) generates data on holes in the packing of data structures and classes in compiled code. It can also the size of structures and how they fit within the system's cache lines. + +### BinSkim + +[BinSkim](https://github.com/Microsoft/binskim) is a binary static analysis tool that provides security and correctness results for Windows Portable Executable and *nix ELF binary formats diff --git a/03-Style.md b/03-Style.md index f9e1f91..7f8607d 100644 --- a/03-Style.md +++ b/03-Style.md @@ -9,6 +9,23 @@ C++ allows for arbitrary-length identifier names, so there's no reason to be ter are common examples. *snake_case* has the advantage that it can also work with spell checkers, if desired. +## Establishing A Style Guideline + +Whatever style guidelines you establish, be sure to implement a `.clang-format` file that specifies the style you expect. While this cannot help with naming, it is particularly important for an open source project to maintain a consistent style. + +Every IDE and many editors have support for clang-format built in or easily installable with an add-in. + + * VSCode: [Microsoft C/C++ extension for VS Code](https://github.com/Microsoft/vscode-cpptools) + * CLion: https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html + * VisualStudio https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.ClangFormat#review-details + * Resharper++: https://www.jetbrains.com/help/resharper/2017.2/Using_Clang_Format.html + * Vim + * https://github.com/rhysd/vim-clang-format + * https://github.com/chiel92/vim-autoformat + * XCode: https://github.com/travisjeffery/ClangFormat-Xcode + + + ## Common C++ Naming Conventions * Types start with upper case: `MyClass`. @@ -18,7 +35,7 @@ are common examples. *snake_case* has the advantage that it can also work with s C++ Standard Library (and other well-known C++ libraries like [Boost](http://www.boost.org/)) use these guidelines: * Macro names use upper case with underscores: `INT_MAX`. - * Template parameter names use camel case: `InputIterator`. + * Template parameter names use Pascal case: `InputIterator`. * All other names use snake case: `unordered_map`. ## Distinguish Private Object Data @@ -225,6 +242,8 @@ It also makes it possible to have two separate files next to each other on one s ## Initialize Member Variables ...with the member initializer list. +For POD types, the performance of an initializer list is the same as manual initialization, but for other types there is a clear performance gain, see below. + ```cpp // Bad Idea class MyClass @@ -239,11 +258,23 @@ private: int m_value; }; +// Bad Idea +// This leads to an additional constructor call for m_myOtherClass +// before the assignment. +class MyClass +{ +public: + MyClass(MyOtherClass t_myOtherClass) + { + m_myOtherClass = t_myOtherClass; + } + +private: + MyOtherClass m_myOtherClass; +}; // 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. +// There is no performance gain here but the code is cleaner. class MyClass { public: @@ -255,33 +286,71 @@ public: private: int m_value; }; + +// Good Idea +// The default constructor for m_myOtherClass is never called here, so +// there is a performance gain if MyOtherClass is not is_trivially_default_constructible. +class MyClass +{ +public: + MyClass(MyOtherClass t_myOtherClass) + : m_myOtherClass(t_myOtherClass) + { + } + +private: + MyOtherClass m_myOtherClass; +}; ``` -In C++11 you may consider always giving each member a default value, e.g. by writing +In C++11 you can assign default values to each member (using `=` or using `{}`). + +### Assigning default values with = + ```cpp // ... // private: - int m_value = 0; + int m_value = 0; // allowed + unsigned m_value_2 = -1; // narrowing from signed to unsigned allowed // ... // ``` -inside the class body. This makes sure that no constructor ever "forgets" to initialize a member object. +This ensures that no constructor ever "forgets" to initialize a member object. + +### Assigning default values with brace initialization + +Using brace initialization does not allow narrowing at compile-time. -Use brace initialization; it does not allow narrowing at compile-time: ```cpp // Best Idea // ... // private: int m_value{ 0 }; // allowed - unsigned m_value_2 { -1 }; // compile-time error, narrowing from signed to unsigned. + unsigned m_value_2 { -1 }; // narrowing from signed to unsigned not allowed, leads to a compile time error // ... // ``` - -Prefer {} initialization over alternatives unless you have a strong reason not to. +Prefer `{}` initialization over `=` unless you have a strong reason not to. Forgetting to initialize a member is a source of undefined behavior bugs which are often extremely hard to find. +If the member variable is not expected to change after the initialization, then mark it `const`. + +```cpp +class MyClass +{ +public: + MyClass(int t_value) + : m_value{t_value} + { + } + +private: + const int m_value{0}; +}; +``` + +Since a const member variable cannot be assigned a new value, such a class may not have a meaningful copy assignment operator. ## Always Use Namespaces @@ -296,7 +365,7 @@ 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++ standard library. It might not warn on the platform you are currently using, but it probably will when you change platforms. -*Note that you can cause integer underflow when peforming some operations on unsigned values. For example:* +*Note that you can cause integer underflow when performing some operations on unsigned values. For example:* ```cpp std::vector v1{2,3,4,5,6,7,8,9}; @@ -332,7 +401,7 @@ They should be preferred to macros, because macros do not honor namespaces, etc. ## Use Operator Overloads Judiciously -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`. +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). @@ -380,9 +449,8 @@ struct S { ## Consider the Rule of Zero -The Rule of Zero states that you do not provide any of the functions that the compiler can provide (copy constructor, assignment operator, move constructor, destructor, move constructor) unless the class you are constructing does some novel form of ownership. +The Rule of Zero states that you do not provide any of the functions that the compiler can provide (copy constructor, copy assignment operator, move constructor, move assignment operator, destructor) unless the class you are constructing does some novel form of ownership. The goal is to let the compiler provide optimal versions that are automatically maintained when more member variables are added. -The [original article](http://flamingdangerzone.com/cxx11/rule-of-zero/) provides the background, while a [follow up article](https://turingtester.wordpress.com/2015/06/27/cs-rule-of-zero/) explains techniques for implementing nearly 100% of the time. - +[This article](http://www.nirfriedman.com/2015/06/27/cpp-rule-of-zero/) provides a background and explains techniques for implementing nearly 100% of the time. diff --git a/04-Considering_Safety.md b/04-Considering_Safety.md index 68028c0..26a87bb 100644 --- a/04-Considering_Safety.md +++ b/04-Considering_Safety.md @@ -2,7 +2,7 @@ ## 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. The [comments on `const` from John Carmack](http://kotaku.com/454293019) are also a good read. +`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. The [comments on `const` from John Carmack](https://web.archive.org/web/20131211065348/https://kotaku.com/454293019) are also a good read. ```cpp // Bad Idea @@ -34,9 +34,9 @@ public: * Always return by value. -references: https://github.com/lefticus/cppbestpractices/issues/21 https://twitter.com/lefticus/status/635943577328095232 +references: https://github.com/lefticus/cppbestpractices/issues/21 https://twitter.com/lefticus/status/635943577328095232 -### Do not pass and return simple types by const ref +### Do not pass and return simple types by const ref ```cpp // Very Bad Idea @@ -47,7 +47,7 @@ public: : m_int_value(t_int_value) { } - + const int& get_int_value() const { return m_int_value; @@ -69,7 +69,7 @@ public: : m_int_value(t_int_value) { } - + int get_int_value() const { return m_int_value; @@ -80,7 +80,7 @@ private: } ``` -Why? Because passing and returning by reference leads to pointer operations instead by much more faster passing values in processor registers. +Why? Because passing and returning by reference leads to pointer operations, instead of much faster passing of values in processor registers. ## Avoid Raw Memory Access @@ -101,7 +101,7 @@ auto mybuffer = std::make_unique(length); // C++14 auto mybuffer = std::unique_ptr(new char[length]); // C++11 // or for reference counted objects -auto myobj = std::make_shared(); +auto myobj = std::make_shared(); // ... // myobj is automatically freed for you whenever it is no longer used. @@ -111,7 +111,7 @@ auto myobj = std::make_shared(); Both of these guarantee contiguous memory layout of objects and can (and should) completely replace your usage of C-style arrays for many of the reasons listed for not using bare pointers. -Also, [avoid](http://stackoverflow.com/questions/3266443/can-you-use-a-shared-ptr-for-raii-of-c-style-arrays) using `std::shared_ptr` to hold an array. +Also, [avoid](http://stackoverflow.com/questions/3266443/can-you-use-a-shared-ptr-for-raii-of-c-style-arrays) using `std::shared_ptr` to hold an array. ## Use Exceptions @@ -120,7 +120,7 @@ Exceptions cannot be ignored. Return values, such as using `boost::optional`, ca Stroustrup, the original designer of C++, [makes this point](http://www.stroustrup.com/bs_faq2.html#exceptions-why) much better than I ever could. ## Use C++-style cast instead of C-style cast -Use the C++-style cast (static\_cast<>, dynamic\_cast<> ...) instead of the C-style cast. The C++-style cast allows more compiler checks and is considerable safer. +Use the C++-style cast (static\_cast<>, dynamic\_cast<> ...) instead of the C-style cast. The C++-style cast allows more compiler checks and is considerably safer. ```cpp // Bad Idea @@ -138,6 +138,8 @@ But consider refactoring of program logic (for example, additional checking on o Variadic functions can accept a variable number of parameters. The probably best known example is printf(). You have the possibility to define this kind of functions by yourself but this is a possible security risk. The usage of variadic functions is not type safe and the wrong input parameters can cause a program termination with an undefined behavior. This undefined behavior can be exploited to a security problem. If you have the possibility to use a compiler that supports C++11, you can use variadic templates instead. +[It is technically possible to make typesafe C-style variadic functions with some compilers](https://github.com/lefticus/cppbestpractices/issues/53) + ## Additional Resources -[How to Prevent The Next Heartbleed](http://www.dwheeler.com/essays/heartbleed.html) by David Wheeler is a good analysis of the current state of code safety and how to ensure safe code. +[How to Prevent The Next Heartbleed](https://dwheeler.com/essays/heartbleed.html) by David Wheeler is a good analysis of the current state of code safety and how to ensure safe code. diff --git a/05-Considering_Maintainability.md b/05-Considering_Maintainability.md index 3116412..2c9a250 100644 --- a/05-Considering_Maintainability.md +++ b/05-Considering_Maintainability.md @@ -16,7 +16,7 @@ namespace my_project { // if the above macro would be expanded, then the following line would be: // static const double 3.14159 = 3.14159; // which leads to a compile-time error. Sometimes such errors are hard to understand. - static const double PI = 3.14159; + static constexpr double PI = 3.14159; }; } ``` @@ -29,7 +29,29 @@ See http://mortoray.com/2015/06/15/get-rid-of-those-boolean-function-parameters/ ## Avoid Raw Loops -Know and understand the existing C++ standard algorithms and put them to use. See [C++ Seasoning](https://www.youtube.com/watch?v=qH6sSOr-yk8) for more details. +Know and understand the existing C++ standard algorithms and put them to use. + + * See [cppreference](https://en.cppreference.com/w/cpp/algorithm) + * Watch [C++ Seasoning](https://www.youtube.com/watch?v=qH6sSOr-yk8) + +Consider a call to `[]` as a potential code smell, indicating that an algorithm was not used where it could have been. + + +## Never Use `assert` With Side Effects + +```cpp +// Bad Idea +assert(set_value(something)); + +// Better Idea +[[maybe_unused]] const auto success = set_value(something); +assert(success); +``` + +The `assert()` will be removed in release builds which will prevent the `set_value` call from ever happening. + +So while the second version is uglier, the first version is simply not correct. + ## Properly Utilize 'override' and 'final' diff --git a/06-Considering_Portability.md b/06-Considering_Portability.md index 228f5c0..5fd89ef 100644 --- a/06-Considering_Portability.md +++ b/06-Considering_Portability.md @@ -6,6 +6,16 @@ Most portability issues that generate warnings are because we are not careful ab http://www.viva64.com/en/a/0010/ +## Use The Standard Library + +### `std::filesystem` + +C++17 added a new `filesystem` library which provides portable filesystem access across all supporting compilers + +### `std::thread` + +C++11's threading capabilities should be utilized over `pthread` or `WinThreads`. + ## Other Concerns Most of the other concerns in this document ultimately come back to portability issues. [Avoid statics](07-Considering_Threadability.md#statics) is particularly of note. diff --git a/08-Considering_Performance.md b/08-Considering_Performance.md index 4d0fab2..467be02 100644 --- a/08-Considering_Performance.md +++ b/08-Considering_Performance.md @@ -33,12 +33,19 @@ template class MyTemplatedType; This is a proactive approach to reduce compilation time and rebuilding dependencies. +*Note: forward declaration does prevent more inlining and optimizations. It's recommended to use Link Time Optimization or Link Time Code Generation for release builds.* + ### Avoid Unnecessary Template Instantiations Templates are not free to instantiate. Instantiating many templates, or templates with more code than necessary increases compiled code size and build time. For more examples see [this article](http://blog2.emptycrate.com/content/template-code-bloat-revisited-smaller-makeshared). +### Avoid Recursive Template Instantiations + +Recursive template instantiations can result in a significant load on the compiler and more difficult to understand code. + +[Consider using variadic expansions and folds when possible instead.](http://articles.emptycrate.com/2016/05/14/folds_in_cpp11_ish.html) ### Analyze the Build @@ -46,15 +53,17 @@ The tool [Templight](https://github.com/mikael-s-persson/templight) can be used After you build using Templight, you will need to analyze the results. The [templight-tools](https://github.com/mikael-s-persson/templight-tools) project provides various methods. (Author's Note: I suggest using the callgrind converter and visualizing the results with kcachegrind). + + ### Firewall Frequently Changing Header Files #### Don't Unnecessarily Include Headers -The compiler has to do something with each include directive it sees. Even if it stops as soon as it seems the `#ifndef` include guard, it still had to open the file and begin processing it. +The compiler has to do something with each include directive it sees. Even if it stops as soon as it sees the `#ifndef` include guard, it still had to open the file and begin processing it. -[include-what-you-use](https://code.google.com/p/include-what-you-use) is a tool that can help you identify which headers you need. +[include-what-you-use](https://github.com/include-what-you-use/include-what-you-use) is a tool that can help you identify which headers you need. #### Reduce the load on the preprocessor @@ -76,7 +85,8 @@ Tools like [cotire](https://github.com/sakra/cotire/) (a plugin for cmake) can h These are not meant to supersede good design - * [ccache](https://ccache.samba.org/) + * [ccache](https://ccache.samba.org/), compile results caching for unix-like operating systems + * [clcache](https://github.com/frerich/clcache), compile results caching for cl.exe (MSVC) * [warp](https://github.com/facebook/warp), Facebook's preprocessor ### Put tmp on Ramdisk @@ -93,8 +103,13 @@ If on Linux, consider using the gold linker for GCC. There's no real way to know where your bottlenecks are without analyzing the code. - * http://developer.amd.com/tools-and-sdks/opencl-zone/codexl/ - * http://www.codersnotes.com/sleepy +A list of code profilers: + * [Intel VTune](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/vtune-profiler.html) + * [Coz - Causal Profiling](https://github.com/plasma-umass/coz) + * [Sleepy](http://www.codersnotes.com/sleepy) + * [Dyninst](https://dyninst.org/) + * [AMD CodeXL](https://github.com/GPUOpen-Archive/CodeXL) + * [lukestackwalker](http://lukestackwalker.sourceforge.net/) ### Simplify the Code @@ -172,7 +187,7 @@ if (caseA) { ```cpp // Better Idea -const std::string somevalue = caseA?"Value A":"Value B"; +const std::string somevalue = caseA ? "Value A" : "Value B"; ``` More complex cases can be facilitated with an [immediately-invoked lambda](http://blog2.emptycrate.com/content/complex-object-initialization-optimization-iife-c11). @@ -265,13 +280,25 @@ for (int i = 0; i < 15; ++i) // obj is still taking up memory for no reason ``` +For C++17 and onwards, consider using init-statement in the `if` and `switch` statements: + +```cpp +if (MyObject obj(index); obj.good()) { + // do something if obj is good +} else { + // do something if obj is not good +} +``` + +[This topic has an associated discussion thread](https://github.com/lefticus/cppbestpractices/issues/52). + ### Prefer `double` to `float`, But Test First -Depending on the situation and the compiler's ability to optimize, one may be faster over the other. Choosing `float` will result in lower precision and may be slower due to conversions. On vectorizable operations `float` may be faster if you are able to sacrifice precision. +Depending on the situation and the compiler's ability to optimize, one may be faster over the other. Choosing `float` will result in lower precision and may be slower due to conversions. On vectorizable operations `float` may be faster if you are able to sacrifice precision. -`double` is the recomended default choice as it is the default type for floating point values in C++. +`double` is the recommended default choice as it is the default type for floating point values in C++. -See this [stackoverflow](http://stackoverflow.com/questions/4584637/double-or-float-which-is-faster) discussion for some more information. +See this [stackoverflow](http://stackoverflow.com/questions/4584637/double-or-float-which-is-faster) discussion for some more information. ### 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. @@ -291,7 +318,7 @@ for (int i = 0; i < 15; ++i) ``` Even if many modern compilers will optimize these two loops to the same assembly code, it is still good practice to prefer `++i`. There is absolutely no reason not to and you can never be certain that your code will not pass a compiler that does not optimize this. -You should be also aware that the compiler will not be able optimize this only for integer types and not necessarily for all iterator or other user defined types. +You should be also aware that the compiler will not be able optimize this only for integer types and not necessarily for all iterator or other user defined types. The bottom line is that it is always easier and recommended to use the pre-increment operator if it is semantically identical to the post-increment operator. ### Char is a char, string is a string @@ -320,5 +347,14 @@ f("world"); // Good Idea auto f = [](const std::string &s) { return my_function("hello", s); }; -f("world") +f("world"); ``` + + +### Know The Standard Library + +Properly use the already highly optimized components of the vendor provided standard library. + +#### `in_place_t` And Related + +Be aware of how to use `in_place_t` and related tags for efficient creation of objects such as `std::tuple`, `std::any` and `std::variant`. diff --git a/09-Considering_Correctness.md b/09-Considering_Correctness.md new file mode 100644 index 0000000..f39af90 --- /dev/null +++ b/09-Considering_Correctness.md @@ -0,0 +1,28 @@ +# Considering Correctness + +## Avoid Typeless Interfaces + + +Bad Idea: + +```cpp +std::string find_file(const std::string &base, const std::string &pattern); +``` + +Better Idea: + +```cpp +std::filesystem::path find_file(const std::filesystem::path &base, const std::regex &pattern); +``` + +The above is better but still suffers from having implicit conversions from `std::string` to `std::filesystem::path` and back. + +Consider using a typesafe library like + + * https://foonathan.net/type_safe/ + * https://github.com/rollbear/strong_type + * https://github.com/joboccara/NamedType + +Note that stronger typing can also allow for more compiler optimizations. + +* [Sorting in C vs C++](Sorting%20in%20C%20vs%20C++.pdf) diff --git a/09-Enable_Scripting.md b/09-Enable_Scripting.md deleted file mode 100644 index 954e9e7..0000000 --- a/09-Enable_Scripting.md +++ /dev/null @@ -1,11 +0,0 @@ -# Enable Scripting - -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 - - * ChaiScript - * AngelScript - * luabind - * sol2 (bindings for Lua) - * SWIG diff --git a/10-Enable_Scripting.md b/10-Enable_Scripting.md new file mode 100644 index 0000000..e22724b --- /dev/null +++ b/10-Enable_Scripting.md @@ -0,0 +1,12 @@ +# Enable Scripting + +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 + + * [ChaiScript](http://chaiscript.com/) + * [AngelScript](http://www.angelcode.com/angelscript/) + * [luabind](http://www.rasterbar.com/products/luabind.html) + * [sol2](https://github.com/ThePhD/sol2) (bindings for Lua) + * [SWIG](http://www.swig.org/) (simplified wrapper and interface generator) + * [pybind11](https://pybind11.readthedocs.io/en/stable/) (Python and modern C++ interoperability) diff --git a/10-Further_Reading.md b/11-Further_Reading.md similarity index 55% rename from 10-Further_Reading.md rename to 11-Further_Reading.md index 9b93870..cc7b721 100644 --- a/10-Further_Reading.md +++ b/11-Further_Reading.md @@ -2,11 +2,13 @@ *Note: This book has now inspired a video series from O'Reilly, [Learning C++ Best Practices](http://shop.oreilly.com/product/0636920049814.do)* - * https://github.com/isocpp/CppCoreGuidelines The C++ Core Guidelines are a set of tried-and-true guidelines, rules, and best practices about coding in C++ +## C++ + + * https://github.com/isocpp/CppCoreGuidelines The C++ Core Guidelines are a set of tried-and-true guidelines, rules, and best practices about coding in C++ * https://www.gitbook.com/book/alexastva/the-ultimate-question-of-programming-refactoring-/details - The Ultimate Question of Programming, Refactoring, and Everything * http://llvm.org/docs/CodingStandards.html - LLVM Coding Standards - very well written * 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.) + * https://google.github.io/styleguide/cppguide.html (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.) * https://isocpp.org/faq/ * http://www.cplusplus.com/ * http://www.gamasutra.com/view/news/128836/InDepth_Static_Code_Analysis.php - Article from John Carmack on the advantages of static analysis @@ -15,3 +17,13 @@ * http://emptycrate.com/ * http://stackoverflow.com/questions/tagged/c%2b%2b-faq?sort=votes&pageSize=15 - StackOverflow C++ FAQ * http://codergears.com/qacenter/ discussion center for C and C++ best practices + * http://www.viva64.com/en/b/0391/ The Ultimate Question of Programming, Refactoring, and Everything + +## CMake + + * https://cmake.org/cmake/help/latest/manual/cmake.1.html - Be aware that there are `--warn` command line options for CMake that can catch some issues. + * https://github.com/Akagi201/learning-cmake + * https://codingnest.com/basic-cmake/ + * https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 - Effective CMake online book + * https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/ + * https://cliutils.gitlab.io/modern-cmake/ - An Introduction to Modern CMake diff --git a/11-Final_Thoughts.md b/12-Final_Thoughts.md similarity index 99% rename from 11-Final_Thoughts.md rename to 12-Final_Thoughts.md index e7f711b..bb4b8f6 100644 --- a/11-Final_Thoughts.md +++ b/12-Final_Thoughts.md @@ -1,4 +1,3 @@ # 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 expressive code. - diff --git a/LICENSE b/LICENSE index 0bde2a8..85c55a6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/. diff --git a/README.md b/README.md index d3cf3c0..ce16a60 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,11 @@ Collaborative Collection of C++ Best Practices -This document is available as a download via [gitbook](https://www.gitbook.com/book/lefticus/cpp-best-practices) - For more information please see the [Preface](01-Preface.md). -This book has inspired an O'Reilly video: [Learning C++ Best Practices](http://shop.oreilly.com/product/0636920049814.do) +This online resource is part of Jason Turner's collection of C++ Best Practices resources. + +* [C++ Best Practices Book](https://leanpub.com/cppbestpractices) +* [C++ Weekly YouTube Channel](https://www.youtube.com/user/lefticus1) +* [The Ultimate CMake/C++ Starter Project](https://github.com/lefticus/cpp_starter_project/) +* [Learning C++ Best Practices - O'Reilly Video](http://shop.oreilly.com/product/0636920049814.do) diff --git a/SUMMARY.md b/SUMMARY.md index a0d963c..c4a9540 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -8,7 +8,7 @@ * [Considering Portability](06-Considering_Portability.md) * [Considering Threadability](07-Considering_Threadability.md) * [Considering Performance](08-Considering_Performance.md) -* [Enable Scripting](09-Enable_Scripting.md) -* [Further Reading](10-Further_Reading.md) -* [Final Thoughts](11-Final_Thoughts.md) - +* [Considering Correctness](09-Considering_Correctness.md) +* [Enable Scripting](10-Enable_Scripting.md) +* [Further Reading](11-Further_Reading.md) +* [Final Thoughts](12-Final_Thoughts.md) diff --git a/Sorting in C vs C++.pdf b/Sorting in C vs C++.pdf new file mode 100644 index 0000000..57f782d Binary files /dev/null and b/Sorting in C vs C++.pdf differ