c++ - 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;
}
- 如果我写“S s”而不是“S s{}”,我有一个错误 --> 使用已删除的函数 S::S()。
- 如果我删除这行“~S() {}”,我有一个错误--> 使用已删除的函数 S::~S()。
在这个网站,https://en.cppreference.com/w/cpp/language/union,据说因为我有一个非默认构造函数/析构函数的成员(字符串),它会删除默认构造函数和union S 的默认析构函数。我的问题是: 为什么?我仍然不明白他们为什么要删除 C++ 中的默认构造函数/析构函数。
- 另外,我听说如果我想将字符串切换为整数,显式调用析构函数很重要,因为它会导致内存泄漏。我的问题是:我需要调用联合析构函数还是字符串析构函数?在这段代码中,如果我需要调用联合析构函数,析构函数什么都不做,这是否意味着我的字符串不会被擦除?如果我需要调用字符串析构函数,我不知道如何编写字符串析构函数。感谢 !
当我运行此代码时,它向我显示:
hello
3
This is my string :
正如我所料,最后一句“这是我的字符串:”没有显示字符串“hello”,因为我已经覆盖了“sa = 3”。但是,似乎 s.str 是空的。我的问题是:为什么 s.str 是空的。这是否意味着编译器已经自动调用了我的字符串的析构函数。感谢!
我知道有诸如 boost 或 variant 之类的替代方案,但我仍然想了解这一点。
解决方案
如果我写“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
当它不是活跃成员时破坏是一个致命的错误。
另外,我听说如果我想将字符串切换为整数,显式调用析构函数很重要,因为它会导致内存泄漏。我的问题是:我需要调用联合析构函数还是字符串析构函数?在这段代码中,如果我需要调用联合析构函数,析构函数什么都不做,这是否意味着我的字符串不会被擦除?如果我需要调用字符串析构函数,我不知道如何编写字符串析构函数。感谢 !
每当您停止使用s
as astring
时,在分配给s.a
或销毁s
whens
被用作字符串之前,您需要调用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();
}
推荐阅读
- java - Java Hash Map(1 个键的多个值)
- javascript - Bootstrap thymeleaf 动态选择列表
- sapui5 - 如何开发混合 Fiori 应用程序并在 Fiori 自定义客户端上启动它?
- c++ - 在六边形图中,如何将 3D 坐标存储为 1D 容器的索引/使用 3D 坐标从 1D 容器中检索元素?
- javascript - Express js后端使用firebase托管从联系页面发送电子邮件在本地运行,但不在Firebase-deploy的URL上
- postgresql - 将 presto 查询输出保存到文件
- html - ::before 伪元素可以是链接吗?
- flutter - 调用模型的工厂构造函数的 Dart/Flutter 问题
- ios - 未找到模块“flutter_facebook_login”
- r - 在 semPaths 图中切换顺序