Buffering

Printing is expensive from a physics perspective

Solution (note: similar to N+1 problem)

stdout is buffered by default, stderr is unbuffered

Makefile

CXX = g++
CXXFLAGS = -std=c++14 -Wall -g -MMD
EXEC = my_program
OBJECTS = main.o dependency.o
DEPENDS = ${OBJECTS:.o=.d}

${EXEC}: ${OBJECTS}
	${CXX} -o ${OBJECTS} ${EXEC}

-include: ${DEPENDS}

.PHONY: not_a_filename

not_a_filename:
	some_command

-MMD flag to generate dependencies

Preprocessor

Transforms code before it reaches the compiler

#include "lib" inserts the contents of the file lib

#define VAR VALUE defines a symbol

Include Guard: Solve the double include problem

#ifndef FILE_H
#define FILE_H
... header file contents
#endif

Constructors

Method called when object is first initialized

Destructors

Method called when object is destroyed

struct Node {
	int data;
	Node *next;
	~Node () { delete next; }
}

The following happens when an object is destructed:

  1. Destructor is called
  2. Dtors of object fields called in reverse declaration order
  3. Superclass is destructed
  4. Space deallocated

Unified Assignment Operator

Node &operator= (Node other) {
	std::swap(this->data, other.data);
	std::swap(this->next, other.next);
	return *this;
}

Tampering

Accessing internal data in an ADT without using public interface - invalidates invariants

Friend

Gives something access to my information - one-way. Useful for iterators in an ADT

Exceptions

Indicates something in program fucked up

Initializer List

Allows for array-style initialization vector<int> v { 1, 2, 3 };

#include <initializer_list>
vector (std::initializer_list<T> init) :
	n { init.size() }, cap { init.size() }, contents { new T[cap] } {
	size_t i = 0;
	for (auto &t: init) contents[i++] = t;
}

Operator and Placement New

Difference between new and malloc: malloc returns NULL, new throws.

Regular new = operator new + placement new

Allocation: operator new(size_t n) (strong guarantee)

Initialization (Placement New): new (address) type

Variadic Arguments and Perfect Forwarding

Same syntax and functionality as spread

template <typename T> class Vector {
	template <typename ...Args> 
	void emplace_back (Args&& ...args, T&& example) {
		new (contents + n) T(args...);
		n++;
	}
}

Exception Safety

A function f can offer 3 different levels of safety once an exception has been handled:

Slicing

Inheritance allows you to do something like Book b = Manga { ... }.

Virtual Methods and Override

// assume same definitions as above
class Book {
	...
	public:
		virtual bool isCool () const { return true; }
}

class Manga : public Book {
	...
	public:
		bool isCool () const override { return hasAnime; }
}

Every class has a "virtual table", or vtable, which contains all of its virtual methods

Every object (instance) has a vptr, a pointer to that table

Casting

For "transforming" types. dynamic_cast<T>(val) is the only one with a runtime effect; all others are compile time casts with O(0) runtime.