This guide focuses on modern C++ standards (C++17 and C++20), which have introduced significant improvements to memory management, type safety, and expressiveness. This document provides a quick reference for the key features you'll encounter throughout this OOP guide.
Smart pointers help manage ownership and lifetime of dynamically allocated objects, reducing the need for manual new/delete.
#include <memory>
// Unique pointer: exclusive ownership
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>();
// Shared pointer: shared ownership with reference counting
std::shared_ptr<MyClass> ptr2 = std::make_shared<MyClass>();Why they matter: Reduce memory leaks and make ownership semantics explicit.
Enables efficient transfer of resources without copying.
class MyClass {
public:
// Move constructor
MyClass(MyClass&& other) noexcept
: data(std::move(other.data)) {}
// Move assignment operator
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
data = std::move(other.data);
}
return *this;
}
private:
std::vector<int> data;
};Why it matters: Improves performance by avoiding unnecessary copies.
Declares intent and allows compiler to enforce correctness.
class MyClass {
public:
// const method: cannot modify member variables
int getValue() const { return value; }
// const reference parameter: won't modify the argument
void process(const std::string& input) { /* ... */ }
private:
int value;
};Why it matters: Catches bugs at compile-time and makes code intentions clear.
Resources are acquired in constructor and released in destructor.
class FileHandler {
public:
explicit FileHandler(const std::string& filename)
: file(filename) {}
private:
std::ifstream file; // Automatically closed by destructor
};
Why it matters: Guarantees cleanup even if exceptions occur.
Unpack values from pairs, tuples, and aggregate types.
auto [name, age] = getPerson();
for (auto& [key, value] : map) {
std::cout << key << ": " << value << std::endl;
}
Why it matters: More readable and less error-prone code.
Explicitly mark virtual function overrides and prevent further overriding.
class Base {
public:
virtual void method() = 0;
};
class Derived : public Base {
public:
void method() override { // Error if method doesn't exist in Base
// Implementation
}
};
class Final : public Derived {
public:
void method() final { // Prevents further overriding
// Implementation
}
};Why it matters: Compiler catches signature mistakes and prevents accidental overrides.
Initialize members at declaration time.
class MyClass {
private:
int count = 0;
std::string name = "default";
std::vector<int> items;
};Why it matters: Ensures predictable initialization.
Explicitly request or forbid compiler-generated methods.
class Copyable {
public:
Copyable(const Copyable&) = default;
Copyable& operator=(const Copyable&) = default;
};
class NonCopyable {
public:
// Prevent copying
NonCopyable(const NonCopyable&) = delete;
NonCopyable& operator=(const NonCopyable&) = delete;
};Why it matters: Makes class semantics explicit.
Declares that a function doesn't throw exceptions.
class MyClass {
public:
// Promises this function won't throw
void swap(MyClass& other) noexcept {
std::swap(data, other.data);
}
private:
std::vector<int> data;
};Why it matters: Enables optimizations and improves correctness guarantees.
Organize code logically and prevent naming conflicts.
// MyLib/MyClass.h
#ifndef MYLIB_MYCLASS_H
#define MYLIB_MYCLASS_H
namespace mylib {
class MyClass {
public:
MyClass();
~MyClass();
};
}
#endifWhy it matters: Professional code organization and maintainability.
Prefer standard containers over raw arrays.
#include <vector>
#include <string>
#include <map>
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::string name = "John";
std::map<std::string, int> ages = {{"Alice", 30}, {"Bob", 25}};Why it matters: Type-safe, feature-rich, and well-tested.
Iterate over containers more readably.
for (int num : numbers) {
std::cout << num << std::endl;
}
for (auto& person : people) {
person.updateAge();
}
Why it matters: Improves clarity and reduces indexing errors.
# With GCC (C++17)
g++ -std=c++17 -Wall -Wextra myfile.cpp -o myfile
# With GCC (C++20)
g++ -std=c++20 -Wall -Wextra myfile.cpp -o myfile
# With CMake
mkdir build && cd build
cmake -DCMAKE_CXX_STANDARD=17 ..
make# Enable all warnings and treat as errors
-Wall -Wextra -Werror
# Enable optimization
-O3
# Enable debugging symbols
-g
# Combined example
g++ -std=c++20 -Wall -Wextra -O3 -g myfile.cpp -o myfile❌ Bad:
void function() {
int* ptr = new int(42);
// ... code ...
delete ptr; // Easy to forget!
}✅ Good:
void function() {
auto ptr = std::make_unique<int>(42);
}❌ Bad:
void processData(std::string input) {
// Can accidentally modify input
}✅ Good:
void processData(const std::string& input) {
// Cannot modify input
}❌ Bad:
class MyClass {
~MyClass() {
delete ptr; // Prone to errors
}
int* ptr;
};✅ Good:
class MyClass {
std::unique_ptr<int> ptr;
};❌ Bad:
class Derived : public Base {
void method() { // Did this override Base::method()?
// Implementation
}
};✅ Good:
class Derived : public Base {
void method() override { // Error if method doesn't exist in Base
// Implementation
}
};Article Updated: January 2026 | Licensed under CC BY-NC-SA 4.0