summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-10-17 17:24:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-10-17 17:24:47 +0200
commita179d867391b05923ef3a6dbbe04eb63f5b264b1 (patch)
treef7db4d164b58d13cd9158400913457dd643b3d44 /doc
parente44edfb832e2491cd17edaa3dc8dc7b9e9265356 (diff)
Move cxx-style.txt to doc/
Diffstat (limited to 'doc')
-rw-r--r--doc/cxx-style.txt66
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.