Unions and std::variant

What are the performance characteristics of std::variant?

How does std::variant perform compared to other ways of storing multiple types, like unions or inheritance? Are there any performance pitfalls to watch out for?

Illustration representing computer hardware

std::variant is generally very efficient, offering performance characteristics similar to a union. The key performance features are:

  1. No heap allocation: Like a union, a variant stores its value directly in the variant object itself. This avoids the overhead of heap allocation and deallocation.
  2. Space efficiency: A variant only needs enough space to store the largest of its alternative types. It does not need the sum of the sizes of all types, as a naive approach like a struct with a member for each type would.
  3. Efficient access: Accessing the current value of a variant is typically just as efficient as accessing a member of a union. The std::get and std::get_if functions are generally implemented as constant-time operations.

In comparison to other approaches:

  • Compared to a union, a variant has slightly more overhead due to the need to store a discriminator (to keep track of which type is currently held). But this overhead is typically very small.
  • Compared to inheritance-based solutions (like a base class with derived classes for each type), a variant is much more space-efficient (as it doesn't need a vtable pointer), and it avoids the overhead of virtual function calls.

However, there are a few potential performance pitfalls to be aware of:

  1. Visitor overhead: If you use std::visit with a lambda that has a complex template parameter (like auto&&), this can lead to significant code bloat, as the lambda will be instantiated for each possible variant type. For maximum performance, prefer simple visitor functions.
  2. Exception handling: Operations that could throw an exception (like std::get when the type doesn't match, or assignment/emplacement when the type's move/copy operations could throw) can be slower due to the need for exception handling. Avoid exceptions where possible for maximum performance.
  3. Large types: If one of the variant's types is much larger than the others, this can lead to wasted space, as the variant will always allocate enough space for the largest type. In such cases, consider using a std::unique_ptr to the large type instead.

Despite these potential pitfalls, std::variant remains a highly performant choice for type-safe value-based polymorphism in most cases, offering better space and time efficiency than alternatives like inheritance.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved