From d5e9a57b0dd8cb333997b5a0ef2e072ed0b76dd9 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 27 Mar 2020 11:32:19 +0200 Subject: Rename cxx-style.txt to build2-cxx-style.txt --- doc/build2-cxx-style.txt | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ doc/cxx-style.txt | 66 ------------------------------------------------ 2 files changed, 66 insertions(+), 66 deletions(-) create mode 100644 doc/build2-cxx-style.txt delete mode 100644 doc/cxx-style.txt diff --git a/doc/build2-cxx-style.txt b/doc/build2-cxx-style.txt new file mode 100644 index 0000000..8e968b8 --- /dev/null +++ b/doc/build2-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. diff --git a/doc/cxx-style.txt b/doc/cxx-style.txt deleted file mode 100644 index 8e968b8..0000000 --- a/doc/cxx-style.txt +++ /dev/null @@ -1,66 +0,0 @@ -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. -- cgit v1.1