首页 > 解决方案 > C++对union的一些误解

问题描述

我是 C++ 新手,我对联合的工作方式有一些疑问。这是我的代码:

#include <iostream>
using namespace std;



union S
{

    std::string str;
    int a;

~S() {}
};

int main()
{
    S s {};
    s.str = "hello";

std::cout << s.str << std::endl;
s.a = 3;
std::cout << s.a;
    std::cout << "This is my string : " <<  s.str << std::endl;

}

  1. 如果我写“S s”而不是“S s{}”,我有一个错误 --> 使用已删除的函数 S::S()。
  2. 如果我删除这行“~S() {}”,我有一个错误--> 使用已删除的函数 S::~S()。

在这个网站,https://en.cppreference.com/w/cpp/language/union,据说因为我有一个非默认构造函数/析构函数的成员(字符串),它会删除默认构造函数和union S 的默认析构函数。我的问题是: 为什么?我仍然不明白他们为什么要删除 C++ 中的默认构造函数/析构函数。

  1. 另外,我听说如果我想将字符串切换为整数,显式调用析构函数很重要,因为它会导致内存泄漏。我的问题是:我需要调用联合析构函数还是字符串析构函数?在这段代码中,如果我需要调用联合析构函数,析构函数什么都不做,这是否意味着我的字符串不会被擦除?如果我需要调用字符串析构函数,我不知道如何编写字符串析构函数。感谢 !

当我运行此代码时,它向我显示:

hello
3
This is my string :

正如我所料,最后一句“这是我的字符串:”没有显示字符串“hello”,因为我已经覆盖了“sa = 3”。但是,似乎 s.str 是空的。我的问题是:为什么 s.str 是空的。这是否意味着编译器已经自动调用了我的字符串的析构函数。感谢!

我知道有诸如 boost 或 variant 之类的替代方案,但我仍然想了解这一点。

标签: c++constructordestructorunions

解决方案


如果我写“S s”而不是“S s{}”,我有一个错误 --> 使用已删除的函数 S::S()。

S包含 astring并且string必须在使用它之前构建它。您已经通过聚合初始化解决了这个问题,这确保了联合的第一个成员将被正确初始化。

请注意,如果a是第一个成员,它将被初始化,而不是str展示s.str = "hello";一些经典的未定义行为动作。

您还可以通过添加构造您希望用作活动成员的成员的构造函数来满足编译器的要求。然后不管什么顺序。从 C++20 开始,您可以使用指定的初始化程序S s{.str=""};, 来选择要初始化的成员,并且仍然使用聚合初始化来避免编写构造函数

如果我删除这行“~S() {}”,我有一个错误--> 使用已删除的函数 S::~S()。

就像str必须要构建的一样,你还需要有脚手架来确保它在被销毁时str是活动成员时s可以被销毁。这通常需要的不仅仅是一个工会,因为您需要一些簿记来跟踪活动成员。str当它不是活跃成员时破坏是一个致命的错误

另外,我听说如果我想将字符串切换为整数,显式调用析构函数很重要,因为它会导致内存泄漏。我的问题是:我需要调用联合析构函数还是字符串析构函数?在这段代码中,如果我需要调用联合析构函数,析构函数什么都不做,这是否意味着我的字符串不会被擦除?如果我需要调用字符串析构函数,我不知道如何编写字符串析构函数。感谢 !

每当您停止使用sas astring时,在分配给s.a或销毁swhens被用作字符串之前,您需要调用string析构函数来结束str.

所以

s.a = 3;

需要成为

s.str.~string();
s.a = 3;

此外,任何时候您想要创建str活动成员,都需要确保它已构建。

std::cout << "This is my string : " << s.str << std::endl;

需要成为

new (&s.str) std::string("I'm Baaaaaack!");
std::cout << "This is my string : " << s.str << std::endl;

然后,因为str是活动成员,我们应该在main退出之前将其销毁。

s.str.~string();

我们得到的所有捆绑在一起,

#include <iostream>
using namespace std;

union S
{

    std::string str;
    int a;

    ~S()
    {
    }
};

int main()
{
    S s{};
    s.str = "hello";

    std::cout << s.str << std::endl;
    s.str.~string();
    s.a = 3;
    std::cout << s.a;

    new (&s.str) std::string("I'm Baaaaaack!");
    std::cout << "This is my string : " << s.str << std::endl;
    s.str.~string();
}

推荐阅读