map :: emplace在哪一点上创建了一个对象?

时间:2016-05-05 21:09:51

标签: c++ c++11 language-lawyer

std::map::emplace创建对象(即调用构造函数)的点是以标准方式指定的吗?如果是,是否会在检查之前是否存在此类密钥?

在以下情况下,这很重要:

struct X {};
std::map<int, std::unique_ptr<X> > map;

void f(int x) {
    map.emplace(x, new X);
}

如果首先创建对象,那么一切都很酷(构造unique_ptr并拥有资源),但如果在检查后构造它,则在重复键的情况下会发生内存泄漏。

我能在标准中找到所有

  

插入一个用_构造的value_type对象   std::forward<Args>(args)...当且仅当时没有元素   密钥等效于t的密钥的容器。

没有解决我的问题。

1 个答案:

答案 0 :(得分:12)

这确实是未明确的,这部分是为什么C ++ 17添加try_emplace来确定语义。 N3873try_emplace提案的早期版本,对现有措辞进行了很好的讨论。

在一般情况下,它必须是“之前”,因为“之后”是不可实现的,如果它强加了这样的要求,标准就会有缺陷。考虑emplace(piecewise_construct, forward_as_tuple(foo, bar), forward_as_tuple(meow, purr))。因为键和值不需要是可移动的,所以你几乎必须首先构造对象并检查键的存在,因为你不能在没有键的情况下检查键的存在。

然而,实现可能需要特殊情况emplace(key_type, something)并不是不可想象的;当密钥存在时,避免支付所需的分配+构造+销毁+解除分配通常是一件好事。