stl :: unordered_map和stl :: vector的破坏有什么不同

时间:2017-07-05 12:41:49

标签: c++ c++11 c++14

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

我有一段遗留代码,我知道这是异常的罪魁祸首。我们以前memset一个向量,一旦它被更改为unordered_map,它就会在销毁时抛出异常。在源代码中,memsetting一个向量与unordered_map有什么不同?它们都与连续的记忆相互作用......

在我们的代码中,我们有这个。 (我为伪代码道歉,但重点应该是可以理解的......)

val broadcast = builder.add(Broadcast[ByteString](2))

source ~> broadcast ~> fileUpload
          broadcast ~> mimeTypeDetection

稍后我们会这样做......

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

struct STRUCT_A
{
    B b;
};

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

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

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

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

析构函数仍然抛出异常。我觉得这很有趣,并认为这是一个很好的问题......

2 个答案:

答案 0 :(得分:7)

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

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

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

答案 1 :(得分:1)

查看实施容器的来源。

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

std::map中,析构函数尝试遍历_Rb_tree的节点,该节点失败,因为根节点具有空指针。在std::unordered_map中,析构函数调用bucket数组上的__builtin_memset,该数组失败,因为已清除指向数组的指针。