为什么我的结构体在使用 `std::variant` 和 `std::monostate` 时被析构了两次?

25

我正在尝试学习std::variant。在这个例子中,我不理解为什么我不想初始化ab,而是使用std::monostate,类A只被构造一次,但却被析构两次。发生了什么?

#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();
}

运行这个例子会产生以下输出。

Constructing A
Destructing A
Destructing A

9
可能是因为在某个时刻进行了复制构造。你尝试过对复制构造函数进行检测吗? - john
5
ab = A() 构造了一个 A 对象,然后将其移动到变量中。你想要的是 ab.emplace<A>() - Homer512
1
https://godbolt.org/z/7eGTTvorc - paddy
2个回答

37

这一行:

ab = A();

创建一个临时的 A 对象,然后将其移动到 ab 中。
您可以通过添加复制/移动构造函数和赋值运算符来观察此过程:
#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();
}

输出:

Constructing A
Move constructing A
Destructing A
Destructing A

您可以通过使用std::variant::emplace来避免复制/移动。
如果您将上述行替换为:

ab.emplace<A>();

输出应该变成:

Constructing A
Destructing A

15

我在你的代码中添加了2行。

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"; }
};

然后我们可以得到这样的结果:
Constructing A
Copy  constructing A
Destructing A
Destructing A

我不熟悉std::variant,我只希望上述实验能让你更接近真正的答案。:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接