Advanced C++ Programming Techniques

Templates

Function Templates

Function templates enable generic programming by allowing functions to operate with different data types.

#include <iostream>
using namespace std;

template<typename T>
void swapValues(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

void testFunctionTemplate() {
    int x = 10, y = 20;
    swapValues(x, y);
    cout << "x = " << x << ", y = " << y << endl;
    
    double a = 1.5, b = 2.5;
    swapValues(a, b);
    cout << "a = " << a << ", b = " << b << endl;
}

Class Tempaltes

Class templates provide a way to create generic classes that can work with various data types.

#include <string>

template<class NameType, class AgeType>
class Person {
public:
    Person(NameType name, AgeType age) : mName(name), mAge(age) {}
    void display() const {
        cout << "Name: " << mName << ", Age: " << mAge << endl;
    }
private:
    NameType mName;
    AgeType mAge;
};

void testClassTemplate() {
    Person<string, int> person("Alice", 30);
    person.display();
}

Standard Template Library

Container Overview

STL containers provide standardized ways to store and organize data:

  • Sequence Containers: vector, deque, list
  • Associative Containers: set, multiset, map, multimap
  • Container Adapters: stack, queue

Vector Operations

#include <vector>
#include <algorithm>

void demonstrateVector() {
    vector<int> numbers;
    
    // Insert elements
    numbers.push_back(10);
    numbers.push_back(20);
    numbers.push_back(30);
    
    // Iterate through elements
    for (auto it = numbers.begin(); it != numbers.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Sort elements
    sort(numbers.begin(), numbers.end());
    
    // Access elements
    cout << "First element: " << numbers.front() << endl;
    cout << "Last element: " << numbers.back() << endl;
}

String Manipulation

#include <string>

void demonstrateString() {
    string text = "Hello";
    
    // Concatenation
    text += " World";
    
    // Find substring
    size_t pos = text.find("World");
    if (pos != string::npos) {
        cout << "Found at position: " << pos << endl;
    }
    
    // Extract substring
    string sub = text.substr(6, 5);
    cout << "Substring: " << sub << endl;
}

Algorithm Usage

STL algorithms provide powerful operations for containers:

#include <algorithm>
#include <vector>

void demonstrateAlgorithms() {
    vector<int> data = {5, 2, 8, 1, 9};
    
    // Find maximum element
    auto maxIt = max_element(data.begin(), data.end());
    cout << "Maximum: " << *maxIt << endl;
    
    // Count occurrences
    int count = count(data.begin(), data.end(), 5);
    cout << "Count of 5: " << count << endl;
    
    // Transform elements
    transform(data.begin(), data.end(), data.begin(), [](int x) { return x * 2; });
}

Advnaced Container Features

Set Operations

#include <set>

void demonstrateSet() {
    set<int> uniqueNumbers = {1, 2, 3, 4, 5};
    
    // Insert elements
    uniqueNumbers.insert(6);
    
    // Check existence
    if (uniqueNumbers.find(3) != uniqueNumbers.end()) {
        cout << "Found 3" << endl;
    }
    
    // Iterate
    for (const auto& num : uniqueNumbers) {
        cout << num << " ";
    }
    cout << endl;
}

Map Usage

#include <map>

void demonstrateMap() {
    map<string, int> scores;
    scores["Alice"] = 95;
    scores["Bob"] = 87;
    
    // Access elements
    cout << "Alice's score: " << scores["Alice"] << endl;
    
    // Iterate through pairs
    for (const auto& pair : scores) {
        cout << pair.first << ": " << pair.second << endl;
    }
}

List Operations

#include <list>

void demonstrateList() {
    list<int> numbers = {1, 2, 3, 4, 5};
    
    // Add elements
    numbers.push_front(0);
    numbers.push_back(6);
    
    // Remove elements
    numbers.pop_front();
    numbers.pop_back();
    
    // Sort
    numbers.sort();
    
    // Print all elements
    for (const auto& num : numbers) {
        cout << num << " ";
    }
    cout << endl;
}

Functional Programming Concepts

Function Objects

Function objects can maintain state and behave like functions:

#include <functional>

class Counter {
private:
    int count;
public:
    Counter() : count(0) {}
    int operator()() {
        return ++count;
    }
};

void demonstrateFunctionObject() {
    Counter counter;
    cout << counter() << endl; // 1
    cout << counter() << endl; // 2
    cout << counter() << endl; // 3
}

Predicate Functions

Predicate functions return boolean values and are useful for filtering:

#include <algorithm>

bool isEven(int number) {
    return number % 2 == 0;
}

void demonstratePredicate() {
    vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};
    
    // Count even numbers
    int evenCount = count_if(numbers.begin(), numbers.end(), isEven);
    cout << "Even numbers: " << evenCount << endl;
    
    // Find first odd number
    auto oddIt = find_if(numbers.begin(), numbers.end(), [](int n) { return n % 2 == 1; });
    if (oddIt != numbers.end()) {
        cout << "First odd: " << *oddIt << endl;
    }
}

STL Algorithms

#include <numeric>
#include <algorithm>

void demonstrateNumericAlgorithms() {
    vector<int> data = {1, 2, 3, 4, 5};
    
    // Calculate sum
    int sum = accumulate(data.begin(), data.end(), 0);
    cout << "Sum: " << sum << endl;
    
    // Fill container
    vector<int> filled(5, 10); // 5 elements with value 10
    
    // Generate sequence
    iota(filled.begin(), filled.end(), 1); // 1, 2, 3, 4, 5
}

Practical Applications

Employee Management System

#include <map>
#include <vector>
#include <algorithm>

struct Employee {
    string name;
    int salary;
    string department;
};

void processEmployees() {
    vector<Employee> employees = {
        {"John", 50000, "Engineering"},
        {"Jane", 60000, "Marketing"},
        {"Bob", 55000, "Engineering"}
    };
    
    // Group by department
    map<string, vector<Employee>> grouped;
    for (const auto& emp : employees) {
        grouped[emp.department].push_back(emp);
    }
    
    // Display results
    for (const auto& [dept, empList] : grouped) {
        cout << dept << ":" << endl;
        for (const auto& emp : empList) {
            cout << "  " << emp.name << " (" << emp.salary << ")" << endl;
        }
    }
}

Data Processing Pipeline

#include <functional>
#include <algorithm>

void processDataPipeline() {
    vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    
    // Chain operations
    vector<int> result;
    
    // Filter even numbers
    copy_if(input.begin(), input.end(), back_inserter(result),
            [](int x) { return x % 2 == 0; });
    
    // Square them
    transform(result.begin(), result.end(), result.begin(),
              [](int x) { return x * x; });
    
    // Sort descending
    sort(result.begin(), result.end(), greater<int>());
    
    // Print results
    for (const auto& val : result) {
        cout << val << " ";
    }
    cout << endl;
}

Memory Management

Smart Pointers

#include <memory>

void demonstrateSmartPointers() {
    // Unique pointer
    unique_ptr<int> ptr(new int(42));
    cout << *ptr << endl;
    
    // Shared pointer
    shared_ptr<string> sharedStr = make_shared<string>("Hello");
    shared_ptr<string> anotherCopy = sharedStr;
    cout << *sharedStr << " " << *anotherCopy << endl;
}

Container Optimization

void optimizeContainers() {
    // Reserve space when size is known
    vector<int> largeVector;
    largeVector.reserve(1000);
    
    // Use emplace instead of push_back for efficiency
    vector<string> strings;
    strings.emplace_back("Hello");
    
    // Avoid unnecessary copies
    const auto& ref = strings.front();
}

Performance Considerations

Iterator Best Practices

void efficientIteration() {
    vector<int> data(1000000);
    
    // Prefer range-based loops
    for (const auto& item : data) {
        // Process item
    }
    
    // Or use iterators efficiently
    for (auto it = data.begin(); it != data.end(); ++it) {
        // Process *it
    }
}

Algorithm Selection

Choose appropriate algorithms based on container type:

  • For vectors: use random access iterators
  • For lists: prefer sequential operations
  • For sets/maps: leverage logarithmic time complexity

Performance optimizations include:

  • Using reserve() before inserting many elements
  • Choosing appropriate container types
  • Leveraging move semantics where possible
  • Minimizing memory reallocations

These techniques help build efficient, maintainable C++ applications that take full advantage of modern standard library features.

Tags: C++ Templates STL containers algorithms

Posted on Wed, 13 May 2026 14:44:33 +0000 by erth