9 ms·
> When they are as fast as C, they also look like C regardless what it was to begin with. … Unless your language offers appropriate zero-overhead abstractions.
by klmr 9y ago
> When they are as fast as C, they also look like C regardless what it was to begin with.
… Unless your language offers appropriate zero-overhead abstractions. C++, for all its flaws, does this extremely well. Then again, C++ is of course (usually) not garbage collected. The problem with the “write like C” approach is that it forces you to write low-level code, and that is usually messy, not self-documenting, and doesn’t take advantage of advanced type system features (which affects correctness).
- jstimpfle 9y agoProvided that by "extremely well" you mean being able to give up control over allocations, making it easier to spew vectors, and worse, maps, all around the place. I think it was ryg who said on twitter that these abstractions are not really "zero cost". C++ abstractions get you in a mindset that might be detrimental to performance. > The problem with the “write like C” approach is that it forces you to write low-level code No, you have to think in what order to do things. Yes, you have to write low-level code, but not all the time. Ideally you write the low-level code in one place and the high-level code in another place. If you do allocations in your high-level code (which is admittedly what you see in many code bases), you are doing it wrong. (speaking of separation of concerns, for example). This has ramifications on maintainability as well as performance. I'm currently writing a little game engine, where I explore an architecture where these things are neatly separated out. (coincidentally, most allocation is done at compilation time, and much "code" is done by the linker). There is of course still a place for script-style code that lacks an elaborate architecture. And I guess C++ is the right choice to do that if you need "tight loop performance" or need to interface with C code.
- klmr 9y ago> C++ abstractions get you in a mindset that might be detrimental to performance. That certainly depends on the application but having been involved with several high-performance libraries written in C++, I can say confidently that C++ abstractions are largely beneficial. For instance, you can often control and avoid memory allocations (but see below): in particular, if you write algorithms interfaces in the style of the standard library, your code will perform very few, if any, unnecessary allocations, and yet be fairly high-level. > Yes, you have to write low-level code, but not all the time. I was talking specifically in the context of writing low-level C-like code, as discussed by my parent comment. You wouldn’t write “high-level C code” outside of C, there’s no need. > If you do allocations in your high-level code you are doing it wrong. As a blanket statement, I don’t agree with this in C++. If you’re careful you can perform (even dynamic!) allocations in C++. Just make sure that you dispatch to a pool allocator. But of course I agree that this requires care, and lots of code should avoid them.
- jstimpfle 9y ago> I was talking specifically in the context of writing low-level C-like code, as discussed by my parent comment. You wouldn’t write “high-level C code” outside of C, there’s no need. Not sure about that - if you want performance you might need to stick to the C way anyway, so maybe you can't take advantage of programming in a scripting language. I've heard of some cases where game programmers ported their game logic back from their script language to C/C++. > For instance, you can often control and avoid memory allocations (but see below): in particular, if you write algorithms interfaces in the style of the standard library, your code will perform very few, if any, unnecessary allocations, and yet be fairly high-level. Another problem with that approach is binary compatibility. Let's take the infamous std::string as an example (not even a templated class). The implementation is much more likely to change than e.g. const char pointer plus optional length, since also memory management and whatnot is needed. If the implementation changes you are in trouble everywhere, including most of the places where a pointer and size would have been just fine (because no allocation is needed there). That just happened to a coworker who now needs to setup a another system and build new binaries on it to support a customer's "old" platform (Ubuntu 14.04)
- arghwhat 9y agoI believe rust would be a better example here, with zero-overhead being a primary design goal. For C++, it's more of a mixed bag. As long as all the abstractions and language features are compile-time evaluated to what people may consider to be "C-like code", then it's all the same. I don't like the term "C-like code", though. It's not C's fault that fast code looks like that, and it is certainly possible to write "prettier" C code than what people have in mind.
- klmr 9y ago> I believe rust would be a better example here From what I’ve heard you’re almost certainly right. I just don’t know enough about Rust to comment on it (unlike C++).
- xfer 9y agozero-overhead abstraction is also C++'s primary goal. In what way it's mixed bag that is not the same in rust? Rust is basically C++ with lifetimes and a cleaner type-system.
- MaxBarraclough 9y ago> zero-overhead abstraction is also C++'s primary goal But it's not completely 'pure' on that front. LLVM's coding standards prohibit RTTI and exceptions precisely because they aren't zero-overhead. https://llvm.org/docs/CodingStandards.html#do-not-use-rtti-or-exceptions https://llvm.org/docs/CodingStandards.html#do-not-use-rtti-o...
- arghwhat 9y agoThose features are much worse than not just zero-overhead. Not only do they have a very clear overhead, the overhead applies to all code by default. You have to explicitly disable those features at compile-time to avoid the bloat.
- MaxBarraclough 9y ago
- 0xcde4c3db 9y agoC++ allows zero-overhead abstractions, but in my experience it's pretty idiomatic for "stack" variables to implicitly do heap allocations or similar possibly-expensive operations (acquire mutexes/semaphores, exchange IPC messages, etc.) in their constructors. Maybe this isn't true of modern/Core Guidelines C++, but it's true of a lot of code I've seen.
- ahartmetz 9y agoI agree about internal heap allocations in stack variables. I disagree about other expensive operations happening unpredictably in constructors. If a class does something expensive in its constructor, you can generally tell by the kind of class it is. If you know the difference between identity classes and value classes - value classes may allocate but that's about it. Identity classes may be expensive (i.e. more expensive than baseline, which is writing all the memory they use once) to construct but you can generally tell.
- TheCoelacanth 9y agoThat is very true of modern C++ because the idiomatic way of handling the acquisition and release of all resources is to acquire in a constructor (typically either explicitly for a single resources or implicitly by including another object that acquires resources as a member variable for multiple resources). C++ doesn't completely free you from considering whether a type allocates memory on the stack or on the heap, but it does let you limit which code needs to concern itself with where values are allocated to a very small portion of the code. Most code written to work against a std::vector will also work against a std::array unless it is relying on the ability of a std::vector to dynamically resize.
- klmr 9y ago> C++ doesn't completely free you from considering whether a type allocates memory on the stack or on the heap You’re completely right but the way this is phrased shows a common misconception about C++/RAII: it was never about freeing the programmer from considering how to manage memory. Rather, it was about automating the mechanics behind these considerations, and adding a layer of type safety (which C++11 tremendously improved). If you don’t want to think about memory management, use a garbage collected language (but accept that it doesn’t scale to all scenarios). C++ forces you to think about resource management, it just makes the implementation of resource management vastly easier than C.