Skip to content
Chris Pilkington edited this page Mar 2, 2024 · 7 revisions

Correctness

Iteration prefer a const auto reference:

for (const auto& item : things) {
}

Algorithms

rotate - Move a range of items in a list to the left or the right:

// simple rotation to the right
std::vector<int> v{2, 4, 2, 0, 5, 10, 7, 3, 7, 1};
std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());

Performance

  • std::map. One of the slowest structures in the STL at everything it does, specially if used with strings as key. If you want a key-value store use unordered_map or another hashmap. Ive seen std::map as the culprit of slowdowns so many times that i now search for it actively in codebases as potential perf hits. The real usage for std::map (ordered-redblack tree) is so uncommon ive never seen std map used as what it really is.
  • Over-creation of small lived strings. Its getting better with string_view and ranges, but pretty much everything string related will create new strings constantly. Its very easy to see slowdowns due to that. A very common one is to-upper or to-lower as std::string cant compare 2 strings in case-insensitive way.
  • Overuse of dynamic_cast. Never a good sign to see dynamic casts everywhere, but dynamic cast has a cost people often ignore, and the cost can really add up when done at scale.

https://www.reddit.com/r/cpp/comments/n8z331/comment/gxln2g3/?context=3

Structure-Of-Array (SOA):

// SOA
struct S {
  int a[N];
  int b[N];
  int c[N];
};

VS

Array-Of-Structures (AOS):

// AOS
struct S {
  int a;
  int b;
  int c;
};
S s[N];

If the program iterates over the data structure S and only accesses field b, then SOA is better because all memory accesses will be sequential.
However, if the program iterates over the data structure S and does excessive operations on all the fields of the object (i.e. a, b, c), then AOS is better because it’s likely that all the members of the object will reside in the same cache line.
Know your data, know how people are using your code, and optimize your application for those use cases.
https://www.cppstories.com/2021/perf-traps/

Secure Coding

assert() and abort()

Upsides:

  • They are great during testing for validating the current state before an operation.
  • If only run in debug mode then they have no performance overhead in release (But obviously won't do any checking)

Downsides:

  • If run in release mode they kill your application ungracefully, not cleaning up resources. If you are writing a database or web server data can easily be lost or corrupted.
  • If only run in debug then your debug and release builds act differently.

Standards

... safecode.org owasp cheatsheetseries c based toolchain hardening cheat sheet

CMake gcc flags

# Warnings https://caiorss.github.io/C-Cpp-Notes/compiler-flags-options.html
SET(WARNING_FLAGS "-Wall -W -Werror -Wextra -Wpedantic -Wconversion -Wcast-align -Winline -Wunused -Wshadow -Wold-style-cast -Wpointer-arith -Wcast-qual -Wno-missing-braces")

SET(BASIC_WARNING_FLAGS "-Wformat -Wformat-y2k -Winit-self -Wstack-protector -Wunknown-pragmas -Wundef -Wwrite-strings -Wno-unused-parameter -Wno-switch -Woverloaded-virtual -Wsuggest-override -Wmissing-include-dirs -Wuninitialized")

# Hardening https://developers.redhat.com/blog/2018/03/21/compiler-and-linker-flags-gcc
SET(HARDENING_FLAGS "-Werror=format-security -fno-exceptions -fno-rtti -D_FORTIFY_SOURCE=2 -fpie -Wl,-pie -Wl,-z,defs -Wl,-z,now -Wl,-z,relro -fplugin=annobin -fstack-clash-protection -fstack-protector-strong -fcf-protection")

# Optimisation Flags
SET(OPTIMISATION_FLAGS "-O3 -flto -finline-functions -funroll-loops -fvectorize")

# Add definitions, compiler switches, etc.
ADD_DEFINITIONS("-std=c++20 ${WARNING_FLAGS} ${BASIC_WARNING_FLAGS} ${HARDENING_FLAGS} ${OPTIMISATION_FLAGS}")