4 ms·
The article goes even further than that: When all else is equal, prefer push_back to emplace_back. It still shows the example of using emplace_back with a pre-e
by MaxBarraclough 6y ago
The article goes even further than that: When all else is equal, prefer push_back to emplace_back. It still shows the example of using emplace_back with a pre-existing object, which as you say, isn't the point of emplace_back. It also states that it's more work for the compiler, stating that the template resolution seems more complex, and suggesting it's likely to bloat compile times. That's a more persuasive point (hard numbers are provided at the end of the article), I wonder if more work has been done on this.
The author seems to be an advanced C++ programmer, but doesn't seem to properly acknowledge that, as you say, The premise of of emplace_back is that you use it for calling the constructor of the object in place. The only instance of proper use of emplace_back is in
widgets.emplace_back(foo, bar, baz);
I was surprised to see no follow-up for this example:
auto w = Widget(1,2,3);
widgets.emplace_back(w); // Fixed? Nope!
No mention of the obvious fix:
widgets.emplace_back(1,2,3);
I don't mean to 'pile on', but, a pet peeve of mine: emplace_back is not magic C++11 pixie dust. This isn't saying anything. You could say garbage collection isn't magic, or error-correcting codes aren't magic, or sound type systems aren't magic. To say that something isn't magic is an empty statement, especially when it's something like emplace_back which introduces an important new ability.
- Sebb767 6y ago> To say that something isn't magic is an empty statement I think this is said to express "simply replacing that function call/method/... without changing your calls/methods/coding style is not going to magically solve your problems". Which is true in the push_back/emplace_back case (you need to adjust your call). GC, on the other hand, is magic pixie dust, if my definition is correct ;)
- MaxBarraclough 6y ago> I think this is said to express "simply replacing that function call/method/... without changing your calls/methods/coding style is not going to magically solve your problems" I agree, but you're doing all the work in conjuring this interpretation. Saying it's not magic doesn't say anything substantial. If it were possible to mechanically replace all references to push_back by emplace_back for an easy performance boost, then we wouldn't need emplace_back to be its own member function, it would just be a compiler optimisation. You have to make shallow and localised changes to make proper use of emplace_back, but isn't that the best we can hope for? Far easier than parallelism, say, where sweeping architectural changes may be necessary.
- Koshkin 6y ago> auto w = Widget(1,2,3); Note that unlike in Java or C# this is not the right way to initialize a variable in C++.
- MaxBarraclough 6y agoGreat point, I'd missed that! It should be: Widget w(1,2,3);
- xdavidliu 6y agoHerb Sutter offers another viewpoint: In particular: #5 on that page: "we see that the right-hand style is not only more robust and maintainable for the reasons already given, but also arguably cleaner and more regular with the type consistently on the right when it is mentioned" [1] https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/ https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style...
- MaxBarraclough 6y agoI don't think Herb's points apply to an ordinary declare-an-object-and-immediately-initialize-using-the-constructor, do they? He gives an example using aggregate initialization, but that's not the same thing: // Classic C++ declaration order // Modern C++ style employee e{ empid }; auto e = employee{ empid }; widget w{ 12, 34 }; auto w = widget{ 12, 34 }; He makes the case that it's nicer to use auto pretty much wherever we can, to avoid repeating ourselves regarding type, and to avoid unexpected conversions. The auto keyword doesn't apply in our case, there's no way to use auto to simplify a statement like: Widget w(1,2,3);
- Koshkin 6y agoExactly. auto is only useful in contexts where the type is expected to be inferred (by the compiler).
- SloopJon 6y agoActually, he does discuss this in section 4b. He doesn't come out as strongly in favor of it, "The jury is still out on whether to recommend this one wholesale," although he does list what he considers some advantages. He also acknowledges in section 6 that it doesn't work for non-moveable types. Despite my tendencies towards almost-always auto, I can't say that I consistently use auto x = type{init}, but there is certainly nothing wrong with it.
- SloopJon 6y ago> It also states that it's more work for the compiler, stating that the template resolution seems more complex, and suggesting it's likely to bloat compile times. That's a more persuasive point (hard numbers are provided at the end of the article) I take the author's point about the cost of compiling a template, but the benchmark is odd: a thousand functions with a single call to emplace_back(). C++ programmers are (in)famously willing to trade compile-time performance for run-time performance. Complement the compile benchmark with a realistic program benchmark. In a typical program, I would expect emplace_back() to be called many more times than it's compiled.
- hules 6y agoWell I'm willing to trade compile-time performance for run-time performance on parts where it does matter. But these parts are quite rare, most of the code of an application is not a performance hot spot where using emplace_back instead of push_back will make a measurable performance difference. So I think the author about compile time is interesting.
- xuhu 6y agoWhen adding items to maps it becomes less obvious (when learning from examples at least) whether map.emplace({Key(args), Value(args)}) avoids copies for Key, Value, pair<Key, Value>, or all of them.