【问题标题】:What differs in the destruction of stl::unordered_map and stl::vector [closed]stl::unordered_map 和 stl::vector 的破坏有什么不同 [关闭]
【发布时间】:2017-07-05 12:41:49
【问题描述】:

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

我有一段遗留代码,我知道它是异常的罪魁祸首。我们之前 memset 一个向量,一旦将其更改为 unordered_map,它就会在销毁时抛出异常。源代码中的什么使 memsetting 向量与 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));

即使我们 memset 一个 stl::container 也能正常工作!但是,如果我们将 B 类更改为具有映射,则析构函数会发生异常。

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

所以我认为这与向量是连续的有关,所以我将其更改为 unordered_map

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

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

【问题讨论】:

  • 你知道原因。这是未定义的行为。因此,使用矢量它恰好“工作”,但由于您的代码格式错误,它仍然无法工作。
  • "即使我们 memset 一个 STL 容器,它也能正常工作" - 不。
  • memset除了 POD 之外的任何东西都只是一种创造性的方式来扩展你的程序
  • 是的,我理解 memsetting 一个对象会导致未定义的行为 那么.. 问题是什么?未定义的行为是未定义的。使用不同的编译器时,您可能会观察到不同的结果。标准不保证它会以一种特定的方式工作。
  • “是的,我明白 [this] 会导致未定义的行为”和“为什么它适用于向量而不适用于其他容器”并没有一起出现。 UB 就是 UB。

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


【解决方案1】:

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

从更一般的角度考虑,您只能在一般可复制的对象上调用memset。否则你的程序的行为是undefined

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

【讨论】:

  • @PasserBy 如果是这种情况,是不是意味着它不能轻易复制?
  • @NathanOliver 我想像class Circle 这样的东西,它可以简单地复制,但它的半径不应该是负数或类似的东西
  • 呃不管怎样,我就接受这个。我认为 Algirdas Preidžius 很好地说明了 UB 案例是如何特定于编译器的。
  • 出于兴趣,您是否将 StlPort 用于您的 STL 库以“允许”您的向量上的 memset?从内存来看,早期的 StlPort 版本有一个短暂的缓冲区优化,现在由于交换要求,这在 C++11 中是非法的。
【解决方案2】:

查看实施容器的源代码。

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

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

【讨论】:

  • 这是我正在寻找的实际答案,谢谢!一个更深入源代码的答案。
猜你喜欢
  • 2014-08-04
  • 2013-07-21
  • 2014-01-22
  • 1970-01-01
  • 2010-09-29
  • 1970-01-01
相关资源
最近更新 更多