utility


Header <utility>

The <utility> header is part of the C++ Standard Library that provides a collection of utility components. This header contains several useful templates and functions that are widely used in C++ programming. The most notable feature of this header is the std::pair class template, but it also includes other utilities like std::swap, std::move, and std::forward.

Key Characteristics

Example 1: Using std::pair and std::make_pair

#include <utility>
#include <iostream>
#include <string>

int main() {
    // Creating a pair using the constructor
    std::pair<std::string, int> person1("Alice", 30);

    // Creating a pair using make_pair
    auto person2 = std::make_pair("Bob", 25);

    // Accessing pair elements
    std::cout << "Person 1: " << person1.first << ", " << person1.second << " years old" << std::endl;
    std::cout << "Person 2: " << person2.first << ", " << person2.second << " years old" << std::endl;

    // Using structured binding (C++17)
    auto [name, age] = person1;
    std::cout << "Name: " << name << ", Age: " << age << std::endl;

    return 0;
}

Explanation:

Example 2: Using std::swap and Custom Swap Functions

#include <utility>
#include <iostream>
#include <vector>

class MyClass {
public:
    MyClass(int val) : value(val) {}
    int getValue() const { return value; }

    // Custom swap function
    friend void swap(MyClass& a, MyClass& b) noexcept {
        std::cout << "Custom swap called" << std::endl;
        std::swap(a.value, b.value);
    }

private:
    int value;
};

int main() {
    int a = 5, b = 10;
    std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
    std::swap(a, b);
    std::cout << "After swap: a = " << a << ", b = " << b << std::endl;

    std::vector<int> vec1 = {1, 2, 3};
    std::vector<int> vec2 = {4, 5, 6};
    std::cout << "Before swap: vec1[0] = " << vec1[0] << ", vec2[0] = " << vec2[0] << std::endl;
    std::swap(vec1, vec2);
    std::cout << "After swap: vec1[0] = " << vec1[0] << ", vec2[0] = " << vec2[0] << std::endl;

    MyClass obj1(100), obj2(200);
    std::cout << "Before swap: obj1 = " << obj1.getValue() << ", obj2 = " << obj2.getValue() << std::endl;
    std::swap(obj1, obj2);
    std::cout << "After swap: obj1 = " << obj1.getValue() << ", obj2 = " << obj2.getValue() << std::endl;

    return 0;
}

Explanation:

Example 3: Move Semantics with std::move

#include <utility>
#include <iostream>
#include <vector>
#include <string>

class Resource {
public:
    Resource(const std::string& s) : data(s) {
        std::cout << "Constructor called for " << data << std::endl;
    }
    Resource(const Resource& other) : data(other.data) {
        std::cout << "Copy constructor called for " << data << std::endl;
    }
    Resource(Resource&& other) noexcept : data(std::move(other.data)) {
        std::cout << "Move constructor called for " << data << std::endl;
    }
    ~Resource() {
        std::cout << "Destructor called for " << data << std::endl;
    }

private:
    std::string data;
};

int main() {
    std::vector<Resource> resources;

    std::cout << "Adding Resource without move:" << std::endl;
    Resource r1("Resource 1");
    resources.push_back(r1);

    std::cout << "\nAdding Resource with move:" << std::endl;
    Resource r2("Resource 2");
    resources.push_back(std::move(r2));

    std::cout << "\nEnd of main" << std::endl;
    return 0;
}

Explanation:

Example 4: Perfect Forwarding with std::forward

#include <utility>
#include <iostream>
#include <string>

template<typename T>
void printType(T&& t) {
    std::cout << "T is " << (std::is_lvalue_reference<T>::value ? "lvalue" : "rvalue") << std::endl;
}

template<typename T>
void perfectForward(T&& t) {
    std::cout << "Forwarding: ";
    printType(std::forward<T>(t));
}

int main() {
    int x = 10;
    const int cx = 20;

    std::cout << "Forwarding lvalue:" << std::endl;
    perfectForward(x);

    std::cout << "Forwarding const lvalue:" << std::endl;
    perfectForward(cx);

    std::cout << "Forwarding rvalue:" << std::endl;
    perfectForward(5);

    std::cout << "Forwarding string literal:" << std::endl;
    perfectForward("hello");

    return 0;
}

Explanation:

Example 5: Using std::integer_sequence

#include <utility>
#include <iostream>
#include <array>

template<typename T, T... Ints>
void printSequence(std::integer_sequence<T, Ints...> int_seq) {
    std::cout << "Sequence size: " << int_seq.size() << std::endl;
    std::cout << "Values: ";
    ((std::cout << Ints << ' '), ...);
    std::cout << std::endl;
}

template<typename T, std::size_t N, std::size_t... I>
void printArrayImpl(const std::array<T, N>& arr, std::index_sequence<I...>) {
    ((std::cout << arr[I] << ' '), ...);
    std::cout << std::endl;
}

template<typename T, std::size_t N>
void printArray(const std::array<T, N>& arr) {
    printArrayImpl(arr, std::make_index_sequence<N>{});
}

int main() {
    printSequence(std::integer_sequence<int, 1, 2, 3, 4, 5>{});
    printSequence(std::make_integer_sequence<int, 5>{});
    printSequence(std::make_index_sequence<5>{});

    std::array<int, 5> arr = {10, 20, 30, 40, 50};
    std::cout << "Array contents: ";
    printArray(arr);

    return 0;
}

Explanation:

Additional Considerations

  1. Move Semantics: std::move doesn't actually move anything; it casts its argument to an rvalue reference, enabling move semantics.

  2. Perfect Forwarding: std::forward is crucial for implementing perfect forwarding in template functions, preserving value categories.

  3. Pair Comparison: <utility> provides comparison operators for pairs, which compare first elements and then second elements.

  4. C++17 Additions: C++17 added std::as_const for obtaining a const reference to an object.

  5. Performance: Using std::move and std::forward correctly can lead to significant performance improvements by avoiding unnecessary copies.

Summary

The <utility> header in C++ provides a collection of utility components that are fundamental to many C++ programming tasks:

These utilities are essential for modern C++ programming, enabling efficient and flexible code. They are particularly important in template metaprogramming, optimizing resource management, and implementing generic algorithms.

The components in <utility> are designed to work seamlessly with other parts of the C++ Standard Library, making them invaluable tools in a C++ programmer's toolkit. Understanding and correctly using these utilities can lead to more efficient, expressive, and maintainable code.

Related

Previous Page | Course Schedule | Course Content