Back to QuickRef

C++

Modern C++ programming language reference covering syntax, STL, object-oriented programming, and best practices.

cpp c++ programming systems performance

Overview

C++ is a general-purpose programming language that supports procedural, object-oriented, and generic programming. It’s widely used for system programming, game development, embedded systems, and high-performance applications.

Installation

Compilers

# GCC (GNU Compiler Collection)
sudo apt install g++                    # Ubuntu/Debian
brew install gcc                        # macOS
sudo yum install gcc-c++                # CentOS/RHEL

# Clang
sudo apt install clang                  # Ubuntu/Debian
brew install llvm                       # macOS

# Microsoft Visual Studio (Windows)
# Download from https://visualstudio.microsoft.com/

Build Tools

# CMake
sudo apt install cmake                  # Ubuntu/Debian
brew install cmake                      # macOS

# Make
sudo apt install make                   # Usually pre-installed

Basic Syntax

Hello World

#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

Compilation

# Basic compilation
g++ -o program program.cpp

# With debugging info
g++ -g -o program program.cpp

# With optimization
g++ -O2 -o program program.cpp

# C++ standard version
g++ -std=c++17 -o program program.cpp

Data Types

Primitive Types

// Integer types
int num = 42;
short s = 10;
long l = 1000000L;
long long ll = 1000000000LL;

// Unsigned types
unsigned int u = 42u;
unsigned long ul = 1000000UL;

// Floating point
float f = 3.14f;
double d = 3.14159;
long double ld = 3.141592653589793L;

// Character types
char c = 'A';
wchar_t wc = L'A';
char16_t c16 = u'A';
char32_t c32 = U'A';

// Boolean
bool flag = true;

// Auto type deduction
auto x = 42;        // int
auto y = 3.14;      // double
auto z = "hello";   // const char*

Constants

const int MAX_SIZE = 100;
constexpr int SIZE = 10;

// Enumeration
enum Color { RED, GREEN, BLUE };
enum class Status { ACTIVE, INACTIVE, PENDING };

// Using enums
Color c = RED;
Status s = Status::ACTIVE;

Variables and Scope

Variable Declaration

int x;              // Declaration
int y = 10;         // Initialization
int z{15};          // Uniform initialization
int a(20);          // Direct initialization

// Multiple declarations
int m = 1, n = 2, p = 3;

Scope

int global_var = 10;    // Global scope

int main() {
    int local_var = 20;  // Local scope
    
    {
        int block_var = 30;  // Block scope
        // block_var is accessible here
    }
    // block_var is not accessible here
    
    return 0;
}

Functions

Function Declaration

// Function prototype
int add(int a, int b);

// Function definition
int add(int a, int b) {
    return a + b;
}

// Function with default parameters
int multiply(int a, int b = 1) {
    return a * b;
}

// Function overloading
int max(int a, int b) {
    return (a > b) ? a : b;
}

double max(double a, double b) {
    return (a > b) ? a : b;
}

Advanced Functions

// Function templates
template<typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

// Lambda functions
auto lambda = [](int x, int y) { return x + y; };
int result = lambda(5, 3);

// Lambda with capture
int multiplier = 10;
auto multiply_by = [multiplier](int x) { return x * multiplier; };

Control Structures

Conditionals

// if-else
if (x > 0) {
    std::cout << "Positive" << std::endl;
} else if (x < 0) {
    std::cout << "Negative" << std::endl;
} else {
    std::cout << "Zero" << std::endl;
}

// Ternary operator
int result = (x > 0) ? 1 : -1;

// Switch statement
switch (choice) {
    case 1:
        std::cout << "Option 1" << std::endl;
        break;
    case 2:
        std::cout << "Option 2" << std::endl;
        break;
    default:
        std::cout << "Invalid option" << std::endl;
}

Loops

// for loop
for (int i = 0; i < 10; i++) {
    std::cout << i << " ";
}

// Range-based for loop
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
    std::cout << num << " ";
}

// while loop
int i = 0;
while (i < 10) {
    std::cout << i << " ";
    i++;
}

// do-while loop
int j = 0;
do {
    std::cout << j << " ";
    j++;
} while (j < 10);

Pointers and References

Pointers

int x = 10;
int* ptr = &x;          // Pointer to x
int value = *ptr;       // Dereference pointer

// Dynamic memory allocation
int* arr = new int[10]; // Allocate array
delete[] arr;           // Free memory

int* num = new int(42); // Allocate single int
delete num;             // Free memory

References

int x = 10;
int& ref = x;           // Reference to x
ref = 20;               // Changes x to 20

// Function parameters
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

Smart Pointers

#include <memory>

// unique_ptr
std::unique_ptr<int> ptr1 = std::make_unique<int>(42);

// shared_ptr
std::shared_ptr<int> ptr2 = std::make_shared<int>(42);

// weak_ptr
std::weak_ptr<int> weak_ptr = ptr2;

Object-Oriented Programming

Classes and Objects

class Rectangle {
private:
    double width, height;

public:
    // Constructor
    Rectangle(double w, double h) : width(w), height(h) {}
    
    // Default constructor
    Rectangle() : width(0), height(0) {}
    
    // Copy constructor
    Rectangle(const Rectangle& other) 
        : width(other.width), height(other.height) {}
    
    // Destructor
    ~Rectangle() {
        // Cleanup code
    }
    
    // Member functions
    double area() const {
        return width * height;
    }
    
    void setDimensions(double w, double h) {
        width = w;
        height = h;
    }
    
    // Getters
    double getWidth() const { return width; }
    double getHeight() const { return height; }
};

// Usage
Rectangle rect(5.0, 3.0);
double area = rect.area();

Inheritance

// Base class
class Shape {
protected:
    std::string color;
    
public:
    Shape(const std::string& c) : color(c) {}
    
    virtual double area() const = 0;    // Pure virtual function
    virtual void draw() const {
        std::cout << "Drawing a " << color << " shape" << std::endl;
    }
    
    virtual ~Shape() = default;         // Virtual destructor
};

// Derived class
class Circle : public Shape {
private:
    double radius;
    
public:
    Circle(double r, const std::string& c) : Shape(c), radius(r) {}
    
    double area() const override {
        return 3.14159 * radius * radius;
    }
    
    void draw() const override {
        std::cout << "Drawing a " << color << " circle" << std::endl;
    }
};

Polymorphism

// Virtual functions
class Animal {
public:
    virtual void makeSound() const {
        std::cout << "Some generic animal sound" << std::endl;
    }
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void makeSound() const override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() const override {
        std::cout << "Meow!" << std::endl;
    }
};

// Usage
std::vector<std::unique_ptr<Animal>> animals;
animals.push_back(std::make_unique<Dog>());
animals.push_back(std::make_unique<Cat>());

for (const auto& animal : animals) {
    animal->makeSound();  // Polymorphic call
}

Standard Template Library (STL)

Containers

Vector

#include <vector>

std::vector<int> v = {1, 2, 3, 4, 5};
v.push_back(6);
v.pop_back();
int size = v.size();
int element = v[0];

List

#include <list>

std::list<int> l = {1, 2, 3};
l.push_front(0);
l.push_back(4);
l.remove(2);

Map

#include <map>

std::map<std::string, int> m;
m["apple"] = 5;
m["banana"] = 3;
m.insert({"orange", 2});

// Iteration
for (const auto& pair : m) {
    std::cout << pair.first << ": " << pair.second << std::endl;
}

Set

#include <set>

std::set<int> s = {3, 1, 4, 1, 5};  // Automatically sorted, no duplicates
s.insert(2);
s.erase(3);
bool found = s.find(4) != s.end();

Algorithms

#include <algorithm>

std::vector<int> v = {3, 1, 4, 1, 5, 9};

// Sorting
std::sort(v.begin(), v.end());

// Finding
auto it = std::find(v.begin(), v.end(), 4);
if (it != v.end()) {
    std::cout << "Found at position: " << std::distance(v.begin(), it) << std::endl;
}

// Transforming
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });

// Filtering
std::vector<int> filtered;
std::copy_if(v.begin(), v.end(), std::back_inserter(filtered), 
             [](int x) { return x > 5; });

Iterators

std::vector<int> v = {1, 2, 3, 4, 5};

// Forward iterator
for (auto it = v.begin(); it != v.end(); ++it) {
    std::cout << *it << " ";
}

// Reverse iterator
for (auto it = v.rbegin(); it != v.rend(); ++it) {
    std::cout << *it << " ";
}

// Range-based for loop (preferred)
for (int value : v) {
    std::cout << value << " ";
}

Memory Management

Stack vs Heap

// Stack allocation
int x = 10;                    // Automatically managed
int arr[100];                  // Fixed size, stack allocated

// Heap allocation
int* ptr = new int(10);        // Manual management required
int* arr = new int[100];       // Dynamic size, heap allocated

// Don't forget to free
delete ptr;
delete[] arr;

RAII (Resource Acquisition Is Initialization)

class FileHandler {
private:
    std::FILE* file;
    
public:
    FileHandler(const std::string& filename) {
        file = std::fopen(filename.c_str(), "r");
        if (!file) {
            throw std::runtime_error("Cannot open file");
        }
    }
    
    ~FileHandler() {
        if (file) {
            std::fclose(file);
        }
    }
    
    // Delete copy constructor and assignment operator
    FileHandler(const FileHandler&) = delete;
    FileHandler& operator=(const FileHandler&) = delete;
};

Exception Handling

Try-Catch

#include <stdexcept>

try {
    int result = divide(10, 0);
    std::cout << "Result: " << result << std::endl;
} catch (const std::runtime_error& e) {
    std::cerr << "Runtime error: " << e.what() << std::endl;
} catch (const std::exception& e) {
    std::cerr << "General error: " << e.what() << std::endl;
} catch (...) {
    std::cerr << "Unknown error occurred" << std::endl;
}

Custom Exceptions

class DivisionByZeroException : public std::exception {
public:
    const char* what() const noexcept override {
        return "Division by zero is not allowed";
    }
};

int divide(int a, int b) {
    if (b == 0) {
        throw DivisionByZeroException();
    }
    return a / b;
}

Templates

Function Templates

template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

// Usage
int max_int = max(5, 3);
double max_double = max(5.5, 3.3);

Class Templates

template<typename T>
class Stack {
private:
    std::vector<T> elements;
    
public:
    void push(const T& item) {
        elements.push_back(item);
    }
    
    T pop() {
        if (elements.empty()) {
            throw std::runtime_error("Stack is empty");
        }
        T top = elements.back();
        elements.pop_back();
        return top;
    }
    
    bool empty() const {
        return elements.empty();
    }
};

// Usage
Stack<int> int_stack;
Stack<std::string> string_stack;

Template Specialization

template<typename T>
class Container {
public:
    void process() {
        std::cout << "General processing" << std::endl;
    }
};

// Specialization for bool
template<>
class Container<bool> {
public:
    void process() {
        std::cout << "Boolean processing" << std::endl;
    }
};

Modern C++ Features

C++11 Features

// Auto keyword
auto x = 42;
auto y = 3.14;

// Range-based for loop
std::vector<int> v = {1, 2, 3, 4, 5};
for (auto& element : v) {
    element *= 2;
}

// Lambda expressions
auto lambda = [](int x) { return x * 2; };

// nullptr
int* ptr = nullptr;  // Instead of NULL

// Move semantics
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1);  // v1 is now empty

C++14 Features

// Generic lambda
auto lambda = [](auto x, auto y) { return x + y; };

// Return type deduction
auto fibonacci(int n) {
    if (n <= 1) return n;
    return fibonacci(n-1) + fibonacci(n-2);
}

// Binary literals
int binary = 0b101010;

C++17 Features

// Structured bindings
std::map<std::string, int> m = {{"apple", 5}, {"banana", 3}};
for (const auto& [key, value] : m) {
    std::cout << key << ": " << value << std::endl;
}

// if constexpr
template<typename T>
auto process(T value) {
    if constexpr (std::is_integral_v<T>) {
        return value * 2;
    } else {
        return value;
    }
}

File I/O

Reading Files

#include <fstream>
#include <sstream>

// Read entire file
std::ifstream file("input.txt");
std::string content((std::istreambuf_iterator<char>(file)),
                    std::istreambuf_iterator<char>());

// Read line by line
std::ifstream file("input.txt");
std::string line;
while (std::getline(file, line)) {
    std::cout << line << std::endl;
}

Writing Files

#include <fstream>

// Write to file
std::ofstream file("output.txt");
file << "Hello, World!" << std::endl;
file << "Line 2" << std::endl;

// Append to file
std::ofstream file("output.txt", std::ios::app);
file << "Appended line" << std::endl;

Debugging and Best Practices

Debugging

#include <cassert>

// Assertions
assert(x > 0);  // Only in debug builds

// Debug output
#ifdef DEBUG
    std::cout << "Debug: x = " << x << std::endl;
#endif

Best Practices

// Use const correctness
void print(const std::string& message) {
    std::cout << message << std::endl;
}

// Use RAII for resource management
class ResourceManager {
    std::unique_ptr<Resource> resource;
public:
    ResourceManager() : resource(std::make_unique<Resource>()) {}
    // Destructor automatically called
};

// Prefer STL containers over raw arrays
std::vector<int> v(100);  // Instead of int arr[100];

// Use smart pointers instead of raw pointers
std::unique_ptr<int> ptr = std::make_unique<int>(42);

Common Patterns

Singleton Pattern

class Singleton {
private:
    static Singleton* instance;
    Singleton() = default;
    
public:
    static Singleton* getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }
    
    // Delete copy constructor and assignment
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

Factory Pattern

class Product {
public:
    virtual ~Product() = default;
    virtual void use() = 0;
};

class ConcreteProduct : public Product {
public:
    void use() override {
        std::cout << "Using concrete product" << std::endl;
    }
};

class Factory {
public:
    static std::unique_ptr<Product> createProduct() {
        return std::make_unique<ConcreteProduct>();
    }
};

Compilation and Build Systems

CMake

# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyProject)

set(CMAKE_CXX_STANDARD 17)

add_executable(myapp main.cpp utils.cpp)

# Link libraries
target_link_libraries(myapp pthread)

Makefile

# Makefile
CXX = g++
CXXFLAGS = -std=c++17 -Wall -Wextra -g
TARGET = myapp
SOURCES = main.cpp utils.cpp

$(TARGET): $(SOURCES)
	$(CXX) $(CXXFLAGS) -o $(TARGET) $(SOURCES)

clean:
	rm -f $(TARGET)

Performance Tips

Optimization

// Use const references for function parameters
void process(const std::vector<int>& data) {
    // Process data without copying
}

// Use move semantics
std::vector<int> getData() {
    std::vector<int> result(1000);
    // ... fill result
    return result;  // Move semantics applied automatically
}

// Reserve vector capacity
std::vector<int> v;
v.reserve(1000);  // Avoid reallocations

// Use emplace instead of push
std::vector<std::string> v;
v.emplace_back("Hello");  // Construct in place

Memory Optimization

// Use appropriate data types
std::uint8_t small_number = 255;  // Instead of int for small values

// Use object pooling for frequently created objects
class ObjectPool {
    std::vector<std::unique_ptr<Object>> pool;
public:
    std::unique_ptr<Object> acquire() {
        if (pool.empty()) {
            return std::make_unique<Object>();
        }
        auto obj = std::move(pool.back());
        pool.pop_back();
        return obj;
    }
    
    void release(std::unique_ptr<Object> obj) {
        pool.push_back(std::move(obj));
    }
};

Testing

Unit Testing (with Google Test)

#include <gtest/gtest.h>

// Test fixture
class CalculatorTest : public ::testing::Test {
protected:
    void SetUp() override {
        calc = std::make_unique<Calculator>();
    }
    
    std::unique_ptr<Calculator> calc;
};

// Test case
TEST_F(CalculatorTest, Addition) {
    EXPECT_EQ(calc->add(2, 3), 5);
    EXPECT_EQ(calc->add(-1, 1), 0);
}

TEST_F(CalculatorTest, Division) {
    EXPECT_EQ(calc->divide(10, 2), 5);
    EXPECT_THROW(calc->divide(10, 0), std::invalid_argument);
}

Quick Reference

Common Headers

#include <iostream>     // Input/output
#include <vector>       // Dynamic arrays
#include <string>       // String class
#include <algorithm>    // Algorithms
#include <memory>       // Smart pointers
#include <fstream>      // File I/O
#include <map>          // Associative containers
#include <thread>       // Threading

Essential Operators

// Arithmetic
+ - * / %

// Comparison
== != < > <= >=

// Logical
&& || !

// Bitwise
& | ^ ~ << >>

// Assignment
= += -= *= /= %=

// Increment/Decrement
++ --

// Member access
. ->

// Scope resolution
::

See Also

Categories:
programming
Last updated: January 1, 2023