stl::unordered_map 和 stl::vector 的销毁有何不同

What differs in the destruction of stl::unordered_map and stl::vector

本文关键字:stl 何不同 unordered map vector      更新时间:2023-10-16

我正在寻找更详细的答案,而不是UB是UB。

我有一段遗留代码,我知道它是异常的罪魁祸首。我们之前对一个向量进行了内存设置,一旦它被更改为unordered_map它就会在销毁时抛出一个异常。源代码中的哪些因素使模因设置向量与unordered_map不同?它们都与连续的记忆相互作用......

在我们的代码中,我们有这个。(对于伪代码,我深表歉意,但这一点应该还是可以理解的......

class B
{
std::vector<CustomObject> vect;
};
struct STRUCT_A
{
B b;
};

稍后我们这样做...

STRUCT_A m_struct_a;
memset(&m_struct_a, 0, sizeof(STRUCT_A));

即使我们设置了一个 stl::container,这也工作得很好!但是,如果我们将类 B 更改为具有映射,则析构函数上会发生异常。

class B
{
std::map<CustomObject> vect;
};

所以我认为这与向量是连续的有关,所以我把它改成了unordered_map

class B
{
std::unordered_map<CustomObject> vect;
};

析构函数上仍会引发异常。我觉得这很有趣,并认为这是一个值得问的好问题......

是的,::memset包含 STL 容器的类的实例确实是一种绝对疯狂的行为。

更一般地说,您只能在可复制的对象上调用memset。否则,程序的行为是未定义的

有关更多详细信息,请参阅 http://en.cppreference.com/w/cpp/string/byte/memset 和 http://en.cppreference.com/w/cpp/types/is_trivially_copyable

查看实现容器的源代码。

在 libstdc++ 中,std::vector的析构函数调用范围中的每个元素CustomObject::~CustomObject()[begin(), end()),然后解除分配内存。由于memsetvector为 0,因此begin() == end() == 0,范围为空,并且永远不会调用成员的析构函数。同样,释放也很好,因为它会在解除分配之前检查存储是否为非空。

std::map中,析构函数试图遍历_Rb_tree节点,但失败是因为根节点有空指针。在std::unordered_map中,析构函数在存储桶数组上调用__builtin_memset,该数组失败,因为指向数组的指针已被清除。