gpt4 book ai didi

c++ - 有人可以解释这个 C++ union 示例吗?

转载 作者:太空狗 更新时间:2023-10-29 19:51:24 27 4
gpt4 key购买 nike

我在 cppreference.com 上找到了这段代码。这是我见过的最奇怪的 C++,对此我有几个问题:

union S
{
std::string str;
std::vector<int> vec;
~S() {}
};

int main()
{
S s = { "Hello, world" };
// at this point, reading from s.vec is undefined behavior
std::cout << "s.str = " << s.str << '\n';
s.str.~basic_string<char>();
new (&s.vec) std::vector<int>;
// now, s.vec is the active member of the union
s.vec.push_back(10);
std::cout << s.vec.size() << '\n';
s.vec.~vector<int>();
}

我想确保我做对了一些事情。

  1. union 会强制您通过删除默认构造函数来初始化 union 成员之一,在本例中,他使用 Hello World 初始化了字符串。
  2. 在他初始化字符串之后, vector 在技术上还不存在?我可以访问它,但它尚未构建?
  3. 他通过调用其析构函数显式地销毁了字符串对象。在这种情况下,当 S 超出范围时,会调用 ~S() 析构函数吗?如果是这样,在哪个对象上?如果他没有在字符串上显式调用析构函数是不是内存泄漏?我倾向于不,因为字符串会自行清理,但对于 union 我不知道。他自己调用了字符串和 vector 的析构函数,所以 ~S() 析构函数似乎没有用,但是当我删除它时,我的编译器不会让我编译它。
  4. 这是我第一次看到有人使用 new 运算符将对象放入堆栈。在这种情况下,这是现在可以使用 vector 的唯一方法吗?
  5. 当您像他对 vector 那样使用 placement new 时,您不应该对其调用 delete,因为尚未分配新内存。通常,如果您将 new 放置在堆上,则必须 free() 内存以避免泄漏,但在这种情况下,如果他让 vector 和 union 超出范围而不调用析构函数,会发生什么情况?

我发现这真的很令人困惑。

最佳答案

  1. 是的,完全正确。
  2. 因为 vector 和字符串使用相同的底层存储(这就是 union 的工作方式),并且该存储当前包含一个字符串,所以没有地方可以放置 vertor 并尝试访问它将是未定义的。并不是说它还没有建成;就是它不能被构造,因为有一个字符串挡住了路。
  3. 每当 S 超出范围时,它的析构函数就会被调用。在这种情况下,这是 union 的析构函数,它被明确定义为什么也不做(因为 union 不知道哪个成员是事件的,所以它实际上不能做它应该做的事) .因为 union 不知道它的哪个成员是活跃的,如果你不显式地调用字符串的析构函数,它就不知道那里有一个字符串,并且字符串不会被清理。当存在具有非平凡析构函数的 union 成员时,编译器会让您编写自己的析构函数,因为它不知道如何清理它并希望您这样做;在这个例子中,你也不知道如何清理它,所以你在 union 的析构函数中什么都不做,让使用 S 的人手动调用正确元素的析构函数。
  4. 这称为“新放置”,是在现有内存位置构造对象而不是分配新对象的典型方法。除了 union 之外,它还有其他用途,但我相信这是在不使用未定义行为的情况下将 vector 放入该 union 中的唯一方法。
  5. 如第 3 部分所述),当 s 超出范围时,它不知道它包含的是字符串还是 vector 。 ~S 析构函数不执行任何操作,因此您需要使用它自己的析构函数来销毁 vector ,就像字符串一样。

要了解 union 无法自动知道调用哪个析构函数的原因,请考虑以下替代函数:

int maybe_string() {
S s = {"Hello, world"};
bool b;
std::cin >> b;
if (b) {
s.str.~basic_string<char>();
new (&s.vec) std::vector<int>;
}
b = false;
// Now there is no more information in the program for what destructor to call.
}

在函数的最后,编译器无法知道s 包含的是字符串还是 vector 。如果你不手动调用析构函数(假设你有办法告诉你,我认为你不会在这里这样做),它就必须安全行事并且不会破坏任何一个成员。 C++ 的创建者决定让事情简单化,不再自动销毁 union 体的事件成员,而是强制程序员手动完成。

关于c++ - 有人可以解释这个 C++ union 示例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46349720/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com