logo

C++ Cheatsheet

Classes

class Foo {
 public:
  Foo(const Foo& arg);             // copy constructor
  Foo(Foo&& arg);                  // move constructor
  Foo& operator=(const Foo& rhs);  // copy assignment operator
  Foo& operator=(Foo&& rhs);       // move assignment operator

  ~Foo(); // destructor
}

Inheritance

// class A
// class B
class C: public A, public B {
  // ...
};

enum class

enum class Color {
  kRed = 0,
  kBlue,
  kOrange,
};

Interfaces

// interface = a class with only pure virtual methods
class Foo {
public:
  virtual int bar(int a) = 0;
};

class FooImpl : public Foo {
  // ...
}

if / else

if (a < 0) {
    // ...
} else if (a == 0) {
    // ...
} else {
    // ...
}

Switch

switch(var) {
  case 1:
      do_somthing_1();
      break;
  case 2:
      do_somthing_2();
      break;
  default:
      do_somthing_else();
}

Lambda

#include <algorithm>
#include <cmath>

std::sort(x, x + n,
    [](float a, float b) {
        return (std::abs(a) < std::abs(b));
    }
);

Smart Pointers

Smart pointers:

// memory freed when ptr_a goes out of scope
unique_ptr<char> ptr_a(new char('a'));

// reference counted pointer
shared_ptr<char> ptr_b(new char('b'));

// pointer that does not increase reference counts
weak_ptr<char> ptr_c = ptr_b;

// memory freed when ptr_d goes out of scope
// differs from unique_ptr in copy semantics
auto_ptr<char> ptr_d(new char('d'));

Attributes

[[deprecated]]
void Foo(int);

Conversions

auto foo_enum = static_cast<Foo>(foo_number);

Strings

std::string is modifiable; no interning.

String constants

// Bad: std::string is not trivially destructible
constexpr std::string

// Good
constexpr absl::string_view

Strings as storage

class {
  private:
    // Good
    std::string str;

    // Bad: it has no control of the backing string.
    absl::string_view;
}

Raw protobuf string literal

R"pb({
 ...
})pb";

Numbers

// max
int64_t max_int64_t = std::numeric_limits<int64_t>::max();

// infinity
double inf = std::numeric_limits<double>::infinity();

Loops

for (int i = 0; i < items_size; ++i) {
  cout << items[i] << endl;
}

for (int i : items) {
  cout << i << endl;
}

Use const reference:

std::string words[] = { "a", "b", "c", "d" };
for (const std::string& word : words) {
  // ...
}

Loop through maps:

std::map<std::string, int> numbers = {{"a", 0}, {"b", 1}, {"c", 2}};
for (const auto& p : numbers) {
  cout << p.first << ": " << p.second;
}

for (const auto& [key, value] : my_map) {
  printf("%f\n", value);
}

Mutable repeated fields:

for (auto& message : *foo.mutable_values()) {
  message.set_field(true);
}

The traditional while loop, looks the same in C++ and Java.

while (condition) {
  // ...
}

do {
  // ...
} while (condition)

Includes

  • #include <utility> for std::move
  • #include <functional> for std::function
  • #include <string> for std::string

Transitive inclusions

Do not rely on transitive inclusions.

foo.cc should include bar.h even if foo.h already includes bar.h.

main

int main(int argc, char** argv) {
  // ...
  return 0;
}

Conding Conventions

Google C++ Style Guide https://google.github.io/styleguide/cppguide.html

Formatter: clang-format