Most active commenters
  • junon(3)

←back to thread

178 points todsacerdoti | 28 comments | | HN request time: 1.004s | source | bottom
1. codeflo ◴[] No.26340405[source]
I’ve personally never encountered the particular misunderstanding the author dispels here, but I’m sure the post is written from bitter experience. On the one hand, I shouldn’t be that surprised: Unfortunately, programming in C++ is really brutal for people who would rather learn by example than by carefully reading documentation.

But on the other hand, my instinctive reaction is: Come on, is this really something that confuses people? emplace_back is all about constructing something in-place, which is exactly the opposite of moving it there! How can any professional programmer be 180 degrees wrong about the purpose of a function they use regularly?

What I want to say here is that C++ is really hard, and that there are a million subtle things that one simply has to look up instead of making educated guesses. I don’t think people appreciate this difficulty enough.

replies(6): >>26340522 #>>26340785 #>>26344462 #>>26345318 #>>26345544 #>>26346091 #
2. mettamage ◴[] No.26340522[source]
I learn C++ by example by using the VSCode debugger. I prefer it over gdb with tui. It won’t go all the way (e.g. educational/smallish projects only that are single threaded) but by that time a programmer has seen some wonky things happening that they can hypothesize about. In my case:

- dangling pointers

- integer under/overflow

- macro expansion (not via debugger but VSCode helps with this)

- double values not being the same when you expect them to be the same

- Seeing if something is copied or moved [1]

[1] Not sure if this is actually true. But I think it can be true by simply stepping inside the function like emplace_back

replies(1): >>26340935 #
3. xKingfisher ◴[] No.26340785[source]
The article did touch on a possible reason for the misunderstanding.

If you already know from previous versions that push_back makes a copy and that C++11 added move semantics and emplace_back, it's not a huge leap to connect the two. Especially if you don't notice push_back's rvalue overload (or understand rvalues).

And if you're new to C++ and are having all of this thrown at you at once it'd definitely be easy to get some crossed wires.

replies(1): >>26341375 #
4. vbezhenar ◴[] No.26340935[source]
If you're using Linux, run your test programs under valgrind. It'll help you immensely to find memory issues.
replies(1): >>26341317 #
5. readams ◴[] No.26341317{3}[source]
I mostly use address sanitizer these days rather than valgrind. It's fast enough that you can just put it in your default compile flags for debugging.
replies(3): >>26341939 #>>26342018 #>>26345905 #
6. brown9-2 ◴[] No.26341375[source]
As someone new to C++, it seems endlessly confusing that you are supposed to know if a function call is making a copy vs a move by figuring out the signature of the function being called or knowing which one the compiler picks, rather than being explicit about it in the code (with std::move or somehow annotating the call with what you want).
replies(3): >>26341456 #>>26342005 #>>26346289 #
7. xKingfisher ◴[] No.26341456{3}[source]
It's definitely a lot to process.

I found these two articles really helpful when trying to understand moves:

https://abseil.io/tips/55 https://abseil.io/tips/77

Though I'd also say don't worry about it too much, especially at first. If you're copying a lot of temporary objects moving can get you some performance wins, but that's something profiling should be telling you m

replies(1): >>26344848 #
8. scatters ◴[] No.26341939{4}[source]
And it's available for Visual Studio, so you don't even need to be running Linux.
9. junon ◴[] No.26342005{3}[source]
You should always know the signature of a function you're calling. Please be reading docs.

The part I agree with are the method selection semantics. A good rule of thumb (though don't rely on it) is that the "more specific" prototype generally wins.

replies(1): >>26343847 #
10. junon ◴[] No.26342018{4}[source]
Address sanitizers have bitten me before. Valgrind has not, aside from the times it wasn't supported on new macos.

Just be careful.

11. brown9-2 ◴[] No.26343847{4}[source]
I agree you should know what you are calling when writing code, but there is also a need for people to read the code and understand what the behavior will be. My impression is that C++ relies a lot on implicit knowledge.
replies(1): >>26344364 #
12. vlovich123 ◴[] No.26344364{5}[source]
All languages do.
replies(1): >>26346791 #
13. npsimons ◴[] No.26344462[source]
> What I want to say here is that C++ is really hard, and that there are a million subtle things that one simply has to look up instead of making educated guesses. I don’t think people appreciate this difficulty enough.

Very much so. I tell everyone not to bother learning C++, there are so many other better languages out there. Hell, I'm only still using it because of legacy projects

14. jeffbee ◴[] No.26344848{4}[source]
Authors should also try to be aware that for some types there's not a meaningful difference between copy construction and move construction.
15. oconnor663 ◴[] No.26345318[source]
> How can any professional programmer be 180 degrees wrong about the purpose of a function they use regularly

If you have a strong understanding of move semantics, then I agree it would be pretty weird to misunderstand the relationship between move semantics and emplace_back. But how common is it to have a strong understanding of move semantics, really? Can we confidently assume that even 50% of professional C++ programmers have a strong understanding of move semantics? I've known competent C++ devs, who write template metaprograms for fun, who were still surprised to learn basic facts about move semantics like "the destructor of a moved-from object will still be called." I know for certain that I don't have a strong understanding of move semantics, but I wouldn't call myself a C++ programmer either, so at least I'm not dragging down the statistics :)

replies(1): >>26346284 #
16. jdashg ◴[] No.26345544[source]
> Unfortunately, programming in C++ is really brutal for people who would rather learn by example than by carefully reading documentation.

This is a great observation! There's probably a ton of this that feeds the "$lang/api/framework is garbage"/"no it's not" schisms. "Well do you prefer documentation or a REPL?"

replies(2): >>26345671 #>>26346431 #
17. whatshisface ◴[] No.26345671[source]
"A manual is a human-operated type system."
18. usefulcat ◴[] No.26345905{4}[source]
It is faster, but IME valgrind is more thorough. I have an option to run unit tests with valgrind.
19. umvi ◴[] No.26346091[source]
> C++ is really brutal for people who would rather learn by example than by carefully reading documentation

As if the documentation/compiler implementations are otherwise perfect. Quick, does `std::condition_variable::wait_for` use a monotonic clock under the hood?

Here's the docs: https://en.cppreference.com/w/cpp/thread/condition_variable/...

You might think so based on the part that says:

> Note that rel_time must be small enough not to overflow when added to std::chrono::steady_clock::now()."

But I happen to know from actually using it, that not all implementations use a monotonic clock: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861

This led to a rather dramatic time bomb bug in our code that only flared up when GPS (and therefore system time) was being spoofed to replay a specific scenario in the past.

replies(1): >>26349472 #
20. wnissen ◴[] No.26346284[source]
Yes, I think his recommendation to prefer push_back is wrong for that reason. I can't imagine it's easier for the compiler to reason about std::move and destructors compared to inlining the constructor.
replies(1): >>26352514 #
21. gpderetta ◴[] No.26346289{3}[source]
Well ideally functions shouldn't be moving behind your back, i.e if you write:

  foo(someValue);
someValue will bever be implicitly moved. Either you need an explicit cast (i.e. std move) or someValue is actually an expression returing a temporary or an rvalue.

Of course if foo takes someValue by non const reference it might still modify someValue as it wishes (and moving out of it is just one possible mutation). But this is not a specific issue with moves but with functions taking non const references in general, which should be used only sporadically and hopefully the name makes the mutation clear.

22. DougBTX ◴[] No.26346431[source]
In some languages the documentation is available as essentially a property of the documented object, so pulling up docs in the repl is easy. It isn’t quite a binary choice.
23. Yoric ◴[] No.26346791{6}[source]
Well, many languages try to keep this minimal. C++ doesn't.
replies(1): >>26348894 #
24. ziml77 ◴[] No.26348894{7}[source]
And it's nothing new with move/copy semantics either. Even passing by reference is bad for hiding that. Every time I write C++ I'm tempted to take pointers as parameters in places where you'd normally take a reference just so the call site has an indication of what I'm doing.
replies(1): >>26352898 #
25. bombela ◴[] No.26349472[source]
wouldn't that be an implementation bug? Because waiting for a specific amount of time is not the same as waiting for a specific wall clock time to come.
replies(1): >>26349635 #
26. umvi ◴[] No.26349635{3}[source]
Yes, it is an implementation bug. My point being that C++ can be brutal even for people who carefully read the docs.
27. ncmncm ◴[] No.26352514{3}[source]
Nope, he's right. He maybe shouldn't be right, but certain convenience features are still missing from Standard Library components and the language that could someday make him wrong.

It is sometimes right to hold your nose and use std::piecewise_construct.

But most usually it doesn't matter, and worrying about it will distract you from what does matter. So, push_back() unless you know you have a good reason not to. And, you might never encounter one.

Good C++ and naïve C++ are not so different. Both are much better than fake-smart C++.

28. junon ◴[] No.26352898{8}[source]
Totally agree.