25

I am trying to learn std::variant. I do not understand why in this example, where I prefer not to initialize ab yet, and I use std::monostate for that, the class A gets constructed once, but destructed twice. What is happening?

#include <iostream>
#include <variant>

struct A
{
    A() { std::cout << "Constructing A\n"; }
    ~A() { std::cout << "Destructing A\n"; }
};


struct B
{
    B() { std::cout << "Constructing B\n"; }
    ~B() { std::cout << "Destructing B\n"; }
};


int main()
{
    std::variant<std::monostate, A, B> ab;
    ab = A();
}

Running this example gives the output below.

Constructing A
Destructing A
Destructing A
4

2 Answers 2

38

This line:

ab = A();

Is creating a temporary A object, and then moving it into ab.
You can observe this by adding copy/move constructors and assignment operators:

#include <iostream>
#include <variant>

struct A
{
    A()                    { std::cout << "Constructing A\n"; }
    A(A const&)            { std::cout << "Copy constructing A\n"; }
    A(A&&)                 { std::cout << "Move constructing A\n"; }
    A& operator=(A const&) { std::cout << "Copy assigning A\n"; return *this; }
    A& operator=(A&&)      { std::cout << "Move assigning A\n"; return *this; }
    ~A()                   { std::cout << "Destructing A\n"; }
};

struct B
{
};

int main()
{
    std::variant<std::monostate, A, B> ab;
    ab = A();
}

Output:

Constructing A
Move constructing A
Destructing A
Destructing A

You can avoid the copy/move, by using std::variant::emplace.
If you replace the above mentioned line with:

ab.emplace<A>();

The output should become:

Constructing A
Destructing A
Sign up to request clarification or add additional context in comments.

Comments

15

I added 2 lines to your code.

struct A
{
    A() { std::cout << "Constructing A\n"; }
    A(const A& a) { std::cout << "Copy  constructing A\n"; }  // <== here
    ~A() { std::cout << "Destructing A\n"; }
};


struct B
{
    B() { std::cout << "Constructing B\n"; }
    B(const B& a) { std::cout << "Copy  constructing B\n"; }   // <== and here
    ~B() { std::cout << "Destructing B\n"; }
};

Then we can get such result:

Constructing A
Copy  constructing A
Destructing A
Destructing A

I am not familiar with std::variant, I just hope above experiment could take you closer to the real answer. :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.