76

Please explain what is the difference between union and std::variant and why std::variant was introduced into the standard? In what situations should we use std::variant over the old-school union?

Kirill Kobelev
  • 10,252
  • 6
  • 30
  • 51
  • 2
    I think `union` does not allow non-POD objects inside. And even if it kinda does (i.e. program does not crash immediately), it does not ensure that correct destructor is called. – yeputons Feb 07 '17 at 05:26
  • 10
    Everywhere you want type safety and are working with non-trivial types. – user975989 Feb 07 '17 at 05:28
  • 1
    I got contradiction and misconception about std::variant while watching this video by Jason Turner:https://www.youtube.com/watch?v=3wm5QzdddYc –  Feb 07 '17 at 05:31
  • 1
    @yeputons, You can store non-POD objects in a union, but you're responsible for constructing and destroying objects when switching the active member. A union is a common implementation technique for in-place storage in types like `std::optional` and, you guessed it, `std::variant`. – chris Feb 07 '17 at 18:17

1 Answers1

113

Generally speaking, you should prefer variant unless one of the following comes up:

  1. You're cheating. You're doing type-punning or other things that are UB but you're hoping your compiler won't break your code.

  2. You're doing some of the pseudo-punnery that C++ unions are allowed to do: conversion between layout-compatible types or between common initial sequences.

  3. You explicitly need layout compatibility. variant<Ts> are not required to have any particular layout; unions of standard layout types are standard layout.

  4. You need low-level support for in-place switching of objects. Using a memory buffer for such things doesn't provide the trivial copying guarantees that you could get out of a union.

The basic difference between the two is that variant knows which type it stores, while union expects you to keep track of that externally. So if you try to access the wrong item in a variant, you get an exception or nullptr. By contrast, doing so with a union is merely undefined behavior.

union is a lower-level tool, and thus should only be used when you absolutely need that lower-level.

variant also has machinery for doing visitation, which means you get to avoid having a bunch of if statements where you ask "if it is type X, do this. If it is type Y, do that, etc".

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 24
    "merely undefined behavior" is not a phrase I see very often. :-) *Excellent* answer, though. "Cheating" is the primary motivation here, and seems to largely encompass 2 and 4 as well. – Cody Gray - on strike Feb 07 '17 at 09:30
  • 2
    @CodyGray: #2 and #4 are both perfectly legal. They're not really cheating so much as things that look like they're cheating. – Nicol Bolas Feb 07 '17 at 14:14
  • Is there an overhead to using std::variant compared to using an union? – In78 Jan 10 '20 at 06:31
  • 1
    @In78: Of course there is. A union doesn't have to know what type it stores, but a variant does. Therefore, there will at least be memory overhead from having that information. – Nicol Bolas Jan 10 '20 at 14:37
  • 1
    Thanks for the honest and unassuming answer - refreshing to see coming from the C++ community. – Qix - MONICA WAS MISTREATED Mar 18 '20 at 00:31