optional


Header: <optional>

std::optional, introduced in C++17, is a template class that represents an optional value. It provides a way to express the potential absence of a value without resorting to sentinel values or null pointers, enhancing type safety and code clarity.

Key Characteristics

Example 1: Basic Usage

#include <iostream>
#include <optional>
#include <string>

std::optional<std::string> get_middle_name(bool has_middle_name) {
    if (has_middle_name) {
        return "Jane";
    }
    return std::nullopt;
}

int main() {
    auto middle_name = get_middle_name(true);
    if (middle_name) {
        std::cout << "Middle name: " << *middle_name << std::endl;
    } else {
        std::cout << "No middle name" << std::endl;
    }

    return 0;
}

Explanation

Example 2: Error Handling

#include <iostream>
#include <optional>
#include <stdexcept>

std::optional<int> safe_divide(int numerator, int denominator) {
    if (denominator == 0) {
        return std::nullopt;
    }
    return numerator / denominator;
}

int main() {
    auto result = safe_divide(10, 2);
    if (result) {
        std::cout << "Result: " << *result << std::endl;
    } else {
        std::cout << "Division by zero" << std::endl;
    }

    try {
        std::cout << result.value() << std::endl;
        std::cout << safe_divide(5, 0).value() << std::endl;
    } catch (const std::bad_optional_access& e) {
        std::cout << "Exception: " << e.what() << std::endl;
    }

    return 0;
}

Explanation

Example 3: Default Values

#include <iostream>
#include <optional>
#include <string>

int main() {
    std::optional<std::string> opt_str;

    std::cout << "Value or default: " << opt_str.value_or("Default") << std::endl;

    opt_str = "Hello";
    std::cout << "Value or default: " << opt_str.value_or("Default") << std::endl;

    return 0;
}

Explanation

Example 4: Optional as a Class Member

#include <iostream>
#include <optional>
#include <string>

class User {
public:
    User(const std::string& name) : name_(name) {}
    void set_email(const std::string& email) { email_ = email; }
    std::string get_email() const { return email_.value_or("No email set"); }

private:
    std::string name_;
    std::optional<std::string> email_;
};

int main() {
    User user("Alice");
    std::cout << "Email: " << user.get_email() << std::endl;

    user.set_email("alice@example.com");
    std::cout << "Email: " << user.get_email() << std::endl;

    return 0;
}

Explanation

Additional Considerations

Summary

std::optional is a valuable addition to the C++ Standard Library, providing a safe and expressive way to represent optional values. It eliminates the need for sentinel values or null pointers, leading to more robust and readable code.

Key points to remember:

  1. std::optional can either contain a value or be empty
  2. Use has_value() or boolean conversion to check if a value is present
  3. Access the value using * operator, value(), or value_or()
  4. value() throws std::bad_optional_access if the optional is empty
  5. std::nullopt represents an empty optional

By using std::optional, C++ developers can write clearer, safer code when dealing with values that may or may not be present, improving overall code quality and reducing potential errors related to null or sentinel values.

Previous Page | Course Schedule | Course Content