Modules (C++20)

“Modules are othogonal to namespaces.”

lvalues and rvalues

An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it.

A function call can be an lvalue if and only if the return value is a reference.

Boost versus STL

Casts – static_cast reinterpret_cast dynamic_cast const_cast

Arrays can be implicitly converted to pointers without casting - there is no implicit conversion from pointers to arrays. int* can be implicity converted to int const*: there is no implicit conversion from int const* to int*.

You can static cast a derived class pointer to a base class pointer but not the other way around.

Rule of three/five

If you declare any of copy, copy assignment or destructor then you should declare them all. Similarly for C++11 onwards: rule of 5.

See wiki/Rule of three.

  • C++: Understand how rule of 5 (rule of 3 in pre-C++11) is the best way to write exception-safe classes. Understand why it’s a good idea even without exceptions.
  • Function local variables are NOT accessible in the try handler.

See rule of three/five/zero.

class base_of_five_defaults
{
 public:
    base_of_five_defaults(const base_of_five_defaults&) = default;
    base_of_five_defaults(base_of_five_defaults&&) = default;
    base_of_five_defaults& operator=(const base_of_five_defaults&) = default;
    base_of_five_defaults& operator=(base_of_five_defaults&&) = default;
    virtual ~base_of_five_defaults() = default;
};

Classes and structures

The difference between a class and a struct is only the default accesses specifier: public: for struct and private: for class.

Virtual

#include <iostream>

class a {
	public:

		a() { std::cout << "a ctor" << std::endl; }
		virtual ~a() { std::cout << "\ta dtor" << std::endl; }
};

class b : public a {
	public:
		b() { std::cout << "b ctor" << std::endl; }
		virtual ~b() { std::cout << "\tb dtor" << std::endl; }
};

int main() {

		std::cout << std::endl;

		{
			a* _b = new b;

			// If the base class destructor weren't virtual only ~a would be called
			delete _b;
		}

		std::cout << std::endl;

		{
			a* _b = new b[3];

			// Still doesn't work for this
			delete [] _b;
		}

	return 0;
}

noexcept

  • Make destructors noexcept
  • Mark move constructor noexcept

Linkage

If an object or function inside such a translation unit has internal linkage, then that specific symbol is only visible to the linker within that translation unit. If an object or function has external linkage, the linker can also see it when processing other translation units. The static keyword, when used in the global namespace, forces a symbol to have internal linkage. The extern keyword results in a symbol having external linkage.

  • Non-const global variables have external linkage by default

  • Const global variables have internal linkage by default

  • Functions have external linkage by default

  • Always use auto

  • Dynamic Storage Duration

  • Automatic Storage Duration

Anonymous namepsaces

Use to declare many things with internal linkage.

namespace { int variable = 0; }

See linkage.

References