Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

std::expected

Use case

Error handling without exceptions

Explanation

std::expected<T, E> holds either a value or an error. Like Rust’s Result<T, E>. Better than std::optional when you need error info.

Code

#include <cstdint>
#include <cstring>
#include <expected>
#include <print>
#include <utility>

enum class ParseError {
  InvalidMagic,
  TooShort,
};

std::expected<uint32_t, ParseError> parseMagic(const uint8_t *data,
                                               size_t size) {
  if (size < 4) {
    return std::unexpected(ParseError::TooShort);
  }

  uint32_t magic;
  std::memcpy(&magic, data, sizeof(magic));

  // https://en.wikipedia.org/wiki/Mach-O
  if (magic != 0xFEEDFACF && magic != 0xFEEDFACE) {
    return std::unexpected(ParseError::InvalidMagic);
  }

  return magic;
}

int main() {
  std::array<uint8_t, 4> buffer = {0xCF, 0xFA, 0xED, 0xFE};
  auto result = parseMagic(buffer.data(), buffer.size());

  if (result) {
    std::println("Magic: {:#x}", result.value());
  } else {
    std::println("Error: {}", std::to_underlying(result.error()));
  }

  return 0;
}

View on GitHub.

Output

$ ./src/c++23/build/std-expected
Magic: 0xfeedfacf