【问题标题】:unordered_map and emplace, why ctor is called twice?unordered_map 和 emplace,为什么 ctor 被调用两次?
【发布时间】:2020-01-27 15:39:19
【问题描述】:

这是一个示例代码:

struct T
{
    T(int x) : x_(x)
    {}

    T(T&&) = delete;
    T(const T&) = delete;

    int x_;
};

int main()
{
    std::unordered_map<int, T> m;
    m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(2));
    m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(2));

    return 0;
}

第二个 emplace 失败,但 T 构造函数被调用了两次。我认为只有在可以插入时,那个 emplace 才会构造一个对象。你能解释一下吗?

编辑: 我使用 Visual Studio 2017 编译器。

【问题讨论】:

  • 你确定吗?这仅显示了一次构造函数调用:wandbox.org/permlink/pAoaakc0p6ZyN2Xf 也许您应该添加有关编译器 inst 版本和系统的信息?
  • @MarekR int main() 1: 1 T::T(int) x_: 2 int main() 2: 2 T::T(int) x_: 2 等于调用了 2 个构造函数,不是吗?
  • 它不应该调用构造函数两次。这可能是您使用的 STL 实现的错误。在大多数情况下,这不是问题,并且可能会被优化掉,但仍然不应该发生这种情况。考虑将其作为错误报告发送给您使用的编译器。

标签: c++ c++17


【解决方案1】:

来自cppreference

即使容器中已经有一个带有key的元素,也可以构造该元素,在这种情况下,新构造的元素将被立即销毁。

出现这种行为的原因是容器需要构造一个关键对象才能检查它是否已经存在;映射对象必须同时构造,因为它们是同一对象(value_type 对)的成员。

try_emplace(C++17 起)在这种情况下是更好的选择,因为它只会在插入成功时构造映射对象。它之所以能够做到这一点,是因为它将键作为第一个参数,并将映射的对象从剩​​余的参数中移出,从而产生了一个更好的接口:

m.try_emplace(1, 2);
m.try_emplace(1, 2);
              ^ key (copied or moved)
                 ^ mapped_type emplacement args (forwarded)

【讨论】:

    猜你喜欢
    • 2014-12-14
    • 1970-01-01
    • 2021-07-13
    • 2021-11-25
    • 2015-12-24
    • 2012-12-10
    • 2014-01-11
    相关资源
    最近更新 更多