# Best Practices for Using `absl::StatusOr<T>` in Abseil C++

> Master absl::StatusOr<T> best practices! Learn to safely access values, use operator* and value_or for robust C++ error handling in Abseil.

- Repository: [Abseil/abseil-cpp](https://github.com/abseil/abseil-cpp)
- Tags: best-practices
- Published: 2026-07-12

---

**Always check `ok()` before accessing the value, prefer `operator*` over `value()` after validation, and use `value_or()` for safe defaults.**

`absl::StatusOr<T>` is the core error-handling primitive in the [Abseil C++ library](https://github.com/abseil/abseil-cpp). It couples an `absl::Status` with a value of type `T`, guaranteeing that either a **successful value** is present or an **error status** explains the failure. This article covers essential patterns from the Abseil source code to help you write safe, efficient, and maintainable error-handling code.

## Check Success Before Accessing the Value

The `absl::StatusOr<T>` class provides an `ok()` accessor at line 71 in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h) that mirrors `absl::Status::ok()`. All client code should verify success before dereferencing.

```cpp
absl::StatusOr<int> GetCount();
absl::StatusOr<int> count = GetCount();

if (count.ok()) {
  // Safe to access value
  int total = *count;
  LOG(INFO) << "Total = " << total;
} else {
  LOG(ERROR) << "Failed: " << count.status();
}

```

The `ABSL_MUST_USE_RESULT` attribute ensures callers cannot silently ignore a `StatusOr` return value.

## Prefer `operator*` and `operator->` Over `value()`

After confirming `ok()`, use the lightweight dereference operators instead of `value()`. As noted in the source comments at line 39 of [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h), the operators provide direct access without the extra exception or termination risk that `value()` incurs when called on an error state.

```cpp
// Good: Direct access after checking ok()
if (result.ok()) {
  Process(*result);           // operator*
  result->MemberFunction();    // operator->
}

// Avoid: value() throws or terminates on error
int x = result.value();      // Risky without prior ok() check

```

## Use `value_or()` for Safe Defaults

When a default value is acceptable on error, use `value_or()` defined at line 74 in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h). This method constructs the default only when necessary, avoiding unnecessary work on the success path.

```cpp
absl::StatusOr<std::string> ReadConfig();
std::string cfg = ReadConfig().value_or("default.cfg");

```

This pattern is cleaner than explicit branching when you have a sensible fallback.

## Propagate Errors Efficiently

Construct a `StatusOr<T>` directly from a non-OK `absl::Status` using the converting constructor at line 63 in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h). This forwards failures without extra boilerplate.

```cpp
absl::StatusOr<std::unique_ptr<Foo>> CreateFoo(int id) {
  if (id < 0) {
    return absl::Status(absl::StatusCode::kInvalidArgument, "negative id");
  }
  return std::make_unique<Foo>(id);  // Implicit conversion to OK StatusOr
}

```

The move-aware assignment operators at line 40 enable efficient forwarding of temporary values without copies.

## Handle `StatusOr<T*>` with Extra Care

When `T` is a pointer type, the pointer may be null even when `ok()` returns true. Always check both conditions before dereferencing, as documented in the source comments at line 70 of [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h).

```cpp
absl::StatusOr<std::unique_ptr<Bar>> result = BarFactory();
if (!result.ok()) {
  LOG(ERROR) << result.status();
} else if (*result == nullptr) {
  LOG(ERROR) << "Unexpected null pointer";
} else {
  (*result)->DoWork();
}

```

## Use `emplace()` for In-Place Construction

When the value type is expensive to copy, use `emplace()` to build it directly inside the `StatusOr`. The implementation at line 111 in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h) preserves correct status handling even if the constructor throws.

```cpp
absl::StatusOr<std::vector<int>> vec = absl::StatusOr<std::vector<int>>();
vec.emplace(5, 0);  // Constructs vector of 5 zeros with no extra copies

```

## Never Ignore Errors in Production

The `IgnoreError()` method exists solely for static-analysis suppression and should not be called in production code, as explicitly warned in the comments at line 103 of [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h).

```cpp
// Bad: Silences warnings but hides bugs
result.IgnoreError();

// Good: Explicitly handle or CHECK
if (!result.ok()) { /* handle error */ }

```

## Summary

- **Always check `ok()`** before dereferencing a `StatusOr`.
- **Use `operator*` and `operator->`** after validation for zero-overhead access.
- **Leverage `value_or()`** when you need a default value on error.
- **Propagate errors** via the converting constructor from `absl::Status`.
- **Verify pointer validity** in `StatusOr<T*>` even after `ok()` succeeds.
- **Construct in-place** with `emplace()` to avoid expensive copies.
- **Never use `IgnoreError()`** in production code.

## Frequently Asked Questions

### What happens if I call `value()` on an error StatusOr?

The `value()` method terminates the program or throws an exception depending on your build configuration. As implemented in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h), `value()` performs a check internally and calls `FatalMessage()` or throws if the `StatusOr` does not contain a valid value. Use `value()` only when you have already verified `ok()` or when program termination is the desired failure mode.

### How do I handle StatusOr in a function that returns void?

Use `ABSL_MUST_USE_RESULT` annotation on your function to force callers to handle the return value. If you must discard a `StatusOr` legitimately (rare), explicitly check `ok()` and document why the error is safe to ignore. Never use `IgnoreError()` as a shortcut.

### Is StatusOr suitable for high-performance code?

Yes. `absl::StatusOr<T>` is designed with zero-overhead abstraction principles. The `operator*` and `operator->` access the value directly with no runtime checks after you verify `ok()`. The move constructors and `emplace()` method ensure efficient handling of large or non-copyable types. The implementation in [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h) uses careful placement and union storage to minimize overhead.

### Can I use StatusOr with built-in pointers like `StatusOr<int*>`?

Yes, but you must check both `ok()` and the pointer value. A `StatusOr<int*>` can be `ok()` yet contain a null pointer, since the pointer itself is the value being carried. Always validate `*result != nullptr` before dereferencing, as noted in the pointer handling comments at line 70 of [`absl/status/statusor.h`](https://github.com/abseil/abseil-cpp/blob/main/absl/status/statusor.h).