diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-10-17 17:24:47 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-10-17 17:24:47 +0200 |
commit | a179d867391b05923ef3a6dbbe04eb63f5b264b1 (patch) | |
tree | f7db4d164b58d13cd9158400913457dd643b3d44 /doc | |
parent | e44edfb832e2491cd17edaa3dc8dc7b9e9265356 (diff) |
Move cxx-style.txt to doc/
Diffstat (limited to 'doc')
-rw-r--r-- | doc/cxx-style.txt | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/doc/cxx-style.txt b/doc/cxx-style.txt new file mode 100644 index 0000000..8e968b8 --- /dev/null +++ b/doc/cxx-style.txt @@ -0,0 +1,66 @@ +0. Don't try to be clever, prefer value/move semantics + +These days optimizers can often "see through" (via constexpr/inline/lto) and +optimize simple code that uses value semantics to the equivalent (or even +better) "clever" code that tries to avoid extra copies, allocations, etc. + +See also the note on small value optimization. + +1. Modernization + +- use override +- consider constexpr for inline functions (e.g., enum class bitmask operators) +- consider noexcept +? migrate to #pragma once + +2. Almost never auto + +Using auto instead of the actual type often makes code harder to understand. +You may (but don't have to) use auto when (a) the type is spelled out on the +right hand side (e.g., casts, make_*<>() functions, etc), and (b) in cases of +idiomatic use where the type is clear to anyone familiar with C++ and it would +be painful to spell it out explicitly. + +Examples of the latter are lambda initializations, iterator initializations +(e.g, from begin()), and some cases of pair initialization (e.g, from +container's insert()). + +3. Almost never brace-initialization + +We only use brace-initialization syntax when initializing an aggregate or a +container. We can also use it for an aggregate-like initialization of an +aggregate-like class. + +An aggregate-like class is class with public data members only and an +aggregate-like initialization is an initialization that provides initializers +for every such data member. For example: + +struct foo +{ + int x, y; + + foo (int x, int y); + foo (int both); +}; + +foo x {0, 1}; // Ok. +foo x {0}; // Bad. + +For default member variable initialization use assignment syntax, for example: + +struct foo +{ + int i = 123; + string s = string (123, 's'); +}; + +4. Many performance-critical standard types are "small object optimized" + +For example, across all the implementations that we care, std::string can hold +at least 15 characters without allocation. Similarly, std::function can hold a +lambda with at least 2 pointers also without allocation. + +As a result, it is seldom makes sense to resort to elaborate optimizations +such as string pooling. In fact, if we have a string pool that contains mostly +short, SOO strings, then we will most likely hurt performance due to lack of +locality. |