Contrary to what the linked article says, I would say the language of the standard almost guarantees that this code does the wrong thing: it moves the pointer from p, and then destroys the object originally pointed to by p because in the end nothing gets inserted into the map m (since the key constructed from "foo" is already present). [I say "almost" only because the language of the Standard is less clear than one should wish; obviously the question at hand simply wasn't on the mind of whoever wrote this.]
Citing from table 102 in 23.2.4, entry a_uniq.emplace(args), the effect is
Inserts a value_type object t constructed with std::forward<Args>(args)...if and only if there is no element in the container with key equivalent to the key of t.
Here value_type for the case of a std::map is std::pair<const Key, T>, in the example with Key equal to std::string and T equal to std::unique_ptr<Foo>. So the object t referred to is (or would be) constructed as
std::pair<const std::string, std::unique_ptr<Foo>> t("foo", std::move(p));
and the "key of t" is the first component of that pair. As the linked article indicates, the language is imprecise due to the conflation of “construct” and “insert”: one might construe that "if and only if" refers to both of them, and that therefore t is neither constructed nor inserted in case there is an element in the container with key equivalent to the key of t; then in this scenario nothing would be moved from p (because of the lack of construction) and p would not become null. However, there is a logical inconsistency in this reading of the cited phrase: if t should never be constructed, what on earth could the "key of t" refer to? Therefore I think the only reasonable reading of this text is: the object t is (unconditionally) constructed as indicated, and then t is inserted into the container if and only if there is no element in the container with key equivalent to the key of t. In the case t is not inserted (as in the example), the temporary will disappear on returning from the call to emplace, destroying the resource moved into it as it goes.
Of course this does not mean it is impossible for an implementation to do the right thing: separately construct the first (key) component of t, look up that key in the container, and only if it is not found construct the complete pair t (at this time moving the mapped-to object form p to the second component of t) and inserting that. (This does require that the key type is copy or move constructible, since what will become the first component of t is initially constructed in a different place.) It is exactly because such implementation is possible that the article proposes to provide a means to reliably ask for such behaviour. But the current language of the standard does not seem to give licence to such an implementation, and even less an obligation to behave like that.
Let me add that I ran into this problem in practice, because I naively thought that having a nice new method emplace it would certainly be defined to work well with move semantics. So I wrote something along the lines of:
auto p = m.emplace(key,std::move(mapped_to_value)); if (not p.second) // no insertion took place { /* some action with value p.first->second about to be overwritten here */ p.first->second = std::move(mapped_to_value) // replace mapped-to value }
It turned out to be not so, and in my "mapped to" type, which happened to contain both a shared pointer and a unique pointer, the shared pointer component behaved fine, but the unique pointer component would become null in case a previous entry in the map was overwritten. Given that this idiom does not work, I rewrote it to
auto range = m.equal_range(key); if (range.first==range.second) // the key was previously absent; insert a pair m.emplace_hint(range.first,key,std::move(mapped_to_value)); else // the key was present, replace the associated value { /* some action with value range.first->second about to be overwritten here */ range.first->second = std::move(mapped_to_value) // replace mapped-to value }
This is a reasonable work-around that works without much assumptions about the mapped-to type (notably it need not be default-constructible or copy-constructible, just move-constructible and move-assignable).
It looks like this idiom should even work for unordered_map, though I did not try it for that case. In fact looking closer, it works, but the use of emplace_hint is pointless, since unlike for the case of std::map, the method std::unordered_map::equal_range is obliged in case of an absent key to return a pair of iterators both equal to the (uninformative) value returned by std::unordered_map::end, rather than some other pair of equal iterators. Indeed it seems that std::unordered_map::emplace_hint, which is allowed to ignore the hint, is almost forced to do so, since either the key is already present and emplace_hint should do nothing (except gobble up the resources possibly moved into its temporary pair t), or else (no such key is present) there is no way to obtain a useful hint, since neither the methods m.find nor m.equal_range are allowed to return anything else than m.end() when invoked with a key that turns out to be absent.