8

I was wondering if it is OK to always use emplace to replace insert when inserting a single element into a STL container, like set, unordered_set?

From the signature, emplace is simpler and do not involve overloads. Is there any issue with stop using insert and use emplace all the time?

Note: there are SO questions asking about the difference between emplace and insert/push_back etc. (e.g. here, here, and here) I understand the difference, and it seems to me that emplace is better in every way. I just want to confirm if it's OK to deprecate insert.

Community
  • 1
  • 1
thor
  • 21,418
  • 31
  • 87
  • 173

2 Answers2

5

There are some examples here that can be adapted to emplace and insert, showing when the behaviour may differ.

These examples may seem a bit artificial, so I'll give one that will hopefully appear less so:

#include <set>

template <typename T>
T id(T x) { return x; }

int main() {
    std::set<int(*)(int)> s;
    s.insert(id);       // OK
    s.emplace(id);      // error
    s.emplace(id<int>); // OK
}

insert can deduce the template parameter of id because it knows what type it wants. For emplace you get an error unless you explicitly specify.

Community
  • 1
  • 1
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • What a surprise. Thanks. But `emplace` should be OK if no templates involved? – thor Jul 20 '14 at 02:56
  • @TingL You can also have non-template overloaded functions. For these the manual resolution is even worse (you need `static_cast`). – Brian Bi Jul 20 '14 at 17:08
4

Always? No, certainly not.

Consider the following example, which uses std::vector for simplicity (assume uptr is a smart pointer acting generally like std::unique_ptr):

std::vector<uptr<T>> vec;
vec.insert(vec.begin(), new T());

It is exception-safe. A temporary uptr is created to pass to insert, which is moved into the vector. If reallocation of the vector fails, the allocated T is owned by a smart pointer which correctly deletes it.

Compare to:

std::vector<std::uptr<T>> vec;
vec.emplace(vec.begin(), new T());

emplace is not allowed to create a temporary object. The uptr will be created once, in-place in the vector. If reallocation fails, there is no location for in-place creation, and no smart pointer will ever be initialized. The T will be leaked.

Of course, the best alternative is:

std::vector<std::unique_ptr<T>> vec;
vec.insert(vec.begin(), make_unique<T>());

which uses a standard smart pointer and makes the smart pointer creation explicit.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @T.C.: Which you won't notice if you've decided to always use `emplace` instead of `insert`. `emplace` will happily call the explicit constructor. – Ben Voigt Jul 20 '14 at 03:02
  • Right, but the first example isn't exception-safe - it simply won't compile. – T.C. Jul 20 '14 at 03:04
  • Hmm, I would claim that any smart pointer type with ownership semantics that can be implicitly constructed from a raw pointer is too dangerous to be used. – T.C. Jul 20 '14 at 03:11
  • @T.C.: Then all the various things that effortlessly call explicit constructors, like `emplace`, should also be too dangerous? Yes, an `explicit` constructor helps prevent this problem in other scenarios, and emplace happily bypasses that protection. – Ben Voigt Jul 20 '14 at 04:13
  • -1. considering taking care of exceptions thrown when realloc fails is waste of time. – NoSenseEtAl Jul 20 '14 at 04:51
  • @NoSenseEtAl It need not be the memory allocation that failed, `T` might have a copy/move constructor that can throw. In any case, that's a silly reason to downvote an answer that describes an important distinction. Examples on SO are more often contrived than not, and the expectation is you'll look beyond that to the concept that it's trying to teach. Also, can you be certain that there's not a single program out there that doesn't handle `std::bad_alloc`? – Praetorian Jul 20 '14 at 06:23
  • @Praetorian ofc they are, for example I can imagine programs doing trying to get max buffer they can, then if it fails try 80% of that, if that fails 80% of that... but in general exception safety when it comes to bad_alloc just makes code less readable and offers no benefits IMAO. If new fails just die.... – NoSenseEtAl Jul 20 '14 at 17:34
  • daamit, scott meyers agrees with you... :D Ill remove the vote if A gets edited, for now SO wont let me... – NoSenseEtAl Jul 20 '14 at 23:26