struct padding and sizeof, worked precisely

A struct's members aren't packed byte-tight — each is aligned to a boundary matching its own size (a double starts at an offset that's a multiple of 8, an int at a multiple of 4), because the processor reads memory a word at a time, and misaligned reads are slower or, on some architectures, illegal. The compiler inserts padding bytes to enforce this, and the struct's overall size is rounded up to a multiple of its largest member's alignment.
Reordering members to put larger types first minimizes wasted padding — the same data, laid out two different ways:

struct Wasteful {   // 24 bytes
  char a;    // 1 byte, then 7 bytes of padding to align b to 8
  double b;  // 8 bytes
  char c;    // 1 byte, then 7 bytes of padding to round the struct to a multiple of 8
};

struct Packed {      // 16 bytes — same members, reordered
  double b;  // 8 bytes
  char a;    // 1 byte
  char c;    // 1 byte, then 6 bytes of trailing padding
};
            
Worth confirming for yourself rather than trusting a rule of thumb — compile std::cout << sizeof(Wasteful); and check. Two more data points worth knowing: a static member never contributes to sizeof, since there's exactly one copy shared by the whole class rather than one per instance (see constexpr & static); and any virtual function adds a single 8-byte vptr to the object, regardless of how many virtual functions the class declares (see Inheritance & Polymorphism).

RAII, named as the umbrella pattern

Resource Acquisition Is Initialization: tie a resource's lifetime to a stack object's constructor and destructor, so it's released on every exit path automatically. It's covered from the file/exception angle in Exceptions & File I/O and from the memory angle in Smart Pointers — it's named here because it's worth recognizing as one deliberate idiom, not three separate coincidences.

Effective C++: the rule of three, made unavoidable

Scott Meyers' "Effective C++" is still one of the most concrete, actionable references for this material. One item worth calling out on its own: if you want a class to be genuinely uncopyable (a resource that has no sensible copy semantics at all — a database connection, say), the modern way is simply = delete on the copy constructor and copy assignment operator. Older code (and Meyers' original 1990s-era advice, predating = delete) achieved the same thing by privately inheriting from a base class whose copy operations were themselves private:

// modern — C++11 onward
class Connection {
public:
  Connection() = default;
  Connection(const Connection &) = delete;
  Connection & operator=(const Connection &) = delete;
};
            

// the pre-C++11 idiom, still worth recognizing in older codebases
class Uncopyable {
protected:
  Uncopyable() = default;
  ~Uncopyable() = default;
private:
  Uncopyable(const Uncopyable &);              // declared, never defined — private, so callers can't use it
  Uncopyable & operator=(const Uncopyable &);
};
class Connection : private Uncopyable {};   // inherits the unusable copy operations
            
A fuller version, made movable as well as uncopyable, with output tracing exactly when the resource opens, moves, and closes: TopNotchNote/cpp/best_practices_uncopyable_resource.cpp

modern idioms worth defaulting to

IdiomWhy
autolet the compiler deduce the type, especially for verbose iterator/template types — but keep it readable; don't hide an important type from a reader who needs to know it
Range-based forfor (const auto &x : container) instead of manual iterator/index loops — shorter, and impossible to get the loop bounds wrong
enum classa scoped, strongly-typed enum — Color::red can't silently collide with an unrelated enum's red, and can't implicitly convert to int the way plain enum does
std::string_viewa non-owning view into a string — pass this instead of const std::string& when a function only reads the string, avoiding a copy/allocation the caller didn't need to pay for
using over typedefsame purpose, but using also works for template aliases, where typedef syntax gets awkward

enum class Pet { dog, cat, bird };
enum class Mammal { bear, dog };     // no collision with Pet::dog — enum class is scoped

Pet p = Pet::dog;                      // must qualify — Pet::dog, never bare "dog"
// int x = p;                            // error — enum class does NOT implicitly convert to int

using IntVector = std::vector<int>;                 // fine, same as typedef here
template <typename T> using Vec = std::vector<T>;    // using can alias a template; typedef cannot
            

preprocessor macros vs. their modern replacements

The preprocessor runs before compilation and does pure text substitution — it doesn't know about C++ types, scopes, or namespaces at all, which is exactly why it's easy to misuse and why most macro use cases now have a better, type-checked replacement.

#define SQUARE(x) ((x) * (x))     // macro — pure text substitution, no type checking, and a classic bug trap:
SQUARE(a + b)                       // expands to ((a + b) * (a + b)) — the extra parens above save this one
int y = 5;
SQUARE(y++);                         // expands to ((y++) * (y++)) — y is incremented twice, undefined order

constexpr int square(int x) { return x * x; }  // the constexpr replacement: type-checked, no double-evaluation risk
            
Macros still earn their keep for a few things nothing else does cleanly: include guards (though #pragma once covers most of that today), conditional compilation (#ifdef DEBUG), and stringizing (#x turns the token x into the string literal "x", used by some logging/assertion macros to print an expression's source text alongside its value).

beyond the standard library: a Boost quick tour

Boost is a widely-used third-party library collection, notable mainly because several of its components previewed features the standard library later adopted directly — boost::optional became std::optional (C++17), boost::filesystem became std::filesystem (C++17), boost::any became std::any (C++17). If a codebase still uses the Boost versions, it's usually either predates that standard, or needs a Boost feature that never made it into the standard library at all (like boost::signals2 for observer-pattern-style signal/slot connections, or Boost's more complete program_options command-line parsing).
boost::optional<int> maybe; | https://www.boost.org/doc/libs/release/libs/optional/ | a value that may or may not be present — prefer std::optional in new C++17+ code |'bp1'
boost::filesystem::exists(path) | https://www.boost.org/doc/libs/release/libs/filesystem/ | filesystem queries — prefer std::filesystem in new C++17+ code |'bp2'

where to go from here

Testing & Tooling — static analysis (cppcheck) that catches some of these bugs automatically.
Classes & Constructors — = delete and = default in full.
Exceptions & File I/O — RAII from the resource-cleanup angle.
Threading & Concurrency — RAII applied to a std::mutex via lock_guard.

reference

cppreference — enum class
cppreference — std::string_view
boost.org — library documentation