←back to thread

178 points todsacerdoti | 2 comments | | HN request time: 0s | source
Show context
TonyTrapp ◴[] No.26340399[source]
Don’t blindly prefer emplace_back to push_back*

*when using it incorrectly. The premise of of emplace_back is that you use it for calling the constructor of the object in place. Obviously it won't help you if you call a copy constructor instead. I find this article a bit pointless. Clang's suggestion was spot-on and emplace_back would have (potentially) helped if the suggestion was actually followed correctly.

replies(4): >>26340422 #>>26340494 #>>26340600 #>>26341355 #
MaxBarraclough ◴[] No.26341355[source]
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.
replies(4): >>26341490 #>>26341620 #>>26342083 #>>26342447 #
Koshkin ◴[] No.26341620[source]
> 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++.

replies(4): >>26341854 #>>26342638 #>>26342704 #>>26344117 #
nec4b ◴[] No.26344117[source]
It is a completely valid way of initializing a variable in modern C++. Modern compilers will not create a copy assignment, if that is what you are afraid of.
replies(1): >>26344771 #
MaxBarraclough ◴[] No.26344771[source]
> Modern compilers will not create a copy assignment, if that is what you are afraid of.

Probably, but using the canonical syntax removes all doubt, following the C++ language specification. That's a small but real disadvantage in robustness when using the unnecessary assignment, and I'm not aware of any reason to favour using it.

replies(1): >>26346833 #
1. eklitzke ◴[] No.26346833[source]
Copy elision in this example is also required by the language specification (if you're using a modern version of C++).
replies(1): >>26349804 #
2. MaxBarraclough ◴[] No.26349804[source]
Neat, I didn't know that.

I still don't like it though. I'd rather express what I want to happen than express something I don't want to happen in the knowledge that the standard requires my compiler to be sufficiently smart to repair my statement. Consistent behaviour across different language versions is another plus.

If you'll permit me a moment's snark:

Most OOP languages: You can't copy objects. You may copy references to objects. Copying objects is one road to madness. Move semantics is another.

Old C++: You can copy objects, and specify your own copy constructors (which are permitted to side-effect), but the compiler is permitted to optimise away copy operations under certain circumstances. You shouldn't assume your copy constructor will be invoked whenever you see what looks like a copy.

New C++: You can copy objects, and specify your own copy constructors (which are permitted to side-effect), but the compiler is permitted to optimise away copy operations under certain circumstances, and beyond that, is now required to optimise away copy operations in some specific circumstances. You shouldn't assume your copy constructor will be invoked whenever you see what looks like a copy. When you see a copy operation in certain specific contexts, you are permitted to assume your copy constructor will not be invoked.

As with so many discussions of C++, I'm reminded of two quotes:

> Within C++, there is a much smaller and cleaner language struggling to get out.

- Bjarne Stroustrup [0]

> Do you know how the Orcs first came into being? They were elves once, taken by the dark powers, tortured and mutilated. A ruined and terrible form of life. And now... perfected.

- Saruman

[0] https://en.wikiquote.org/wiki/Bjarne_Stroustrup