logo

C++ - Language Concepts

Last Updated: 2022-02-12

State

An object's state is the collective set of its non-static data members' values.

Copying causes a target object t to end up with the same state as the source s, without modifying s.

Storage Duration

Memory in C++ is primarily allocated either on the stack or the heap (with small exceptions for things like string literals and static variables).

Memory Allocation Deallocation Contiguous
automatic stack code block begins code block ends contiguous
dynamic heap new delete not contiguous
static static program begins program ends
thread thread begins thread ends

Notes:

  • automatic: all local objects except for static, extern or thread_local
  • static: variables live for the lifetime of the program, in a separate part of program memory colloquially referred to as "Static Memory." Only one instance exists; objects at namespace scope, or static or extern
  • thread: each thread has its own instance

A variable (that is not explicitly marked as thread_local) has static storage duration if any of the following holds:

  • It has namespace scope.
  • It is a static data member of a class.
  • It is a static variable defined in a function.

Translation Unit

A translation unit = a source file + all (direct or indirect) header files - lines ignored by conditional preprocessing statements.

A translation unit is the input to the compiler to generate an object file.

Linkage

3 levels of linkage

  • no linkage: an entity cannot be referenced via names from anywhere else
  • internal linkage: definitions in a .cc file cannot be referenced outside the file. (Do NOT use internal linkage in .h files) Can be achieved in 2 ways:
    • for all declarations (including functions and variables): place them in unnamed namespaces
    • for functions and variables: declare them static
  • external linkage: The name can be referred to from the scopes in the other translation units.

Keywords vs Identifiers

Keywords are reserved everywhere, identifiers are reserved only in some cases (e.g. final, override, import, module)

Read more: C++ Keywords

Copy Elision

Copy elision: an optimization that applies whenever an object is initialized by copying another object of the same type, and the source object is inaccessible afterward (has gone out of scope or was destroyed as a temporary). When that's the case, the compiler can treat the two objects as occupying the same storage, and just skip the copy constructor.

Something that looks like a copy operation only actually invokes the copy constructor if it results in two distinct names for the value.

Do not std::move local variables in a return statement. This is a performance anti-pattern because it prevents Return Value Optimization where applicable, and is unnecessary in general because the compiler can implicitly move variables.

std::unique_ptr<Foo> MakeFoo() {
  auto result = absl::make_unique<Foo>();
  // ...
  return result; // OK
}

The primary limitation of copy elision is that it applies only during initialization of the destination object (i.e. when it's first created), and requires the source object to be completely inaccessible after the copy.

One Definition Rule

The One Definition Rule (ODR) is an important rule of the C++ programming language that prescribes that objects and non-inline functions cannot have more than one definition in the entire program and template and types cannot have more than one definition by translation unit.

Trivially Destructible

  • formally: the type has no user-defined or virtual destructor and that all bases and non-static members are trivially destructible.
  • informally: the destructor does not do anything, even taking member and base destructors into account.

Check if it is trivially destructible (Since C++11): std::is_trivially_destructible https://en.cppreference.com/w/cpp/types/is_destructible

Examples:

  • fundamental types (like pointers and int) are trivially destructible
  • arrays of trivially destructible types are trivially destructible
  • variables marked with constexpr are trivially destructible.

Curiously recurring template pattern (CRTP)

A class Foo derives from a class template instantiation using Foo itself as a template argument. A.k.a. "F-bounded quantification", "F-bound polymorphism", "Upside-Down Inheritance" (it allows class hierarchies to be extended by substituting different base classes).

It looks like class Foo : public Base<Foo>. The class name Foo also appears in Base<Foo>.

Use case: static polymorphism. This technique achieves a similar effect to the use of virtual functions (emulates the virtual function call system at compile time), without the costs (and some flexibility) of dynamic polymorphism.

Constructor ordering

  • For classes with parents, the parent is constructed first, then the child (recursively, for hierarchies).
  • Member variables within a class are constructed in the order they are declared.
  • Variables within a block (very broadly, between an open brace { and close brace }) are constructed in the order they are declared.

Copy constructor

A copy constructor aims to make a value copy of an object.

The compiler-provided copy constructor copies each data member, calling those members' copy constructors, recursively if necessary.

non-member in unnamed namespace

Writing a non-member in an unnamed namespace has benefits both by making functions internal to a .cc file (moving them out of header files) as well as by making them non-members (moving them out of classes).