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

Ser*_*eyA 9 c++ language-lawyer c++11

std::map::emplace在标准中以某种方式创建对象(即调用构造函数)的点是什么?如果是,是否检查此类密钥存在之前或之后发生?

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

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

void f(int x) {
    map.emplace(x, new X);
}
Run Code Online (Sandbox Code Playgroud)

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

所有我能在标准中找到的是

插入一个value_type对象t,使用std::forward<Args>(args)...if和仅当容器中没有元素且使用等效于t的键的元素构造 .

这没有解决我的问题.

T.C*_*.C. 12

这确实是不明确的,这部分是为什么C++ 17增加try_emplace了解决语义的原因.N3873是该try_emplace提案的早期版本,对现有措辞进行了很好的讨论.

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

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