3 ms·
> So you're (primarily?) referring to "cognitive overhead" rather than more usual meaning of overhead as in "runtime overhead" I'm referring to both. The issue
by CuriousCosmic 3y ago
> So you're (primarily?) referring to "cognitive overhead" rather than more usual meaning of overhead as in "runtime overhead"
I'm referring to both. The issue is that all that complexity makes it very difficult for programmers to write code that the compiler is consistently able to optimise to (or close to) zero overhead. It can be done with enough work and care but for your average C++ developer, they aren't going to be seeing zero overhead for a lot of the things that C++ generally leads us to assume are zero overhead.
> Can you given an example?
To copy the link that TwentyPosts provided (which is coincidentally also the first thing that came to my mind, albeit at a different timestamp) https://youtu.be/rHIkrotSwcc?t=1054 https://youtu.be/rHIkrotSwcc?t=1054.
The issues with `unique_ptr` in particular are that:
- They force the compiler to generate exception code where maybe there isn't any necessary if you pass them into a function. You can elide this by going through and annotating things that you know can't except with noexcept however most people don't even care about noexcept in the first place and consider it line-noise.
- Using move references to unique_ptr instead of pointers adds overhead by forcing the compiler to generate extra memory reads.
- Passing by value should be zero cost but it'd require breaking basically every aspect of the C++ ABI to do so. Because of this you still get a double indirection which adds overhead.
So your average C++ programmer probably won't do #1 which adds the largest overhead and if you need to transfer ownership you have to do #2 or #3. It's only really zero overhead when you can't transfer ownership (`unique_ptr<T> const &`) and even then, now you are looking over your shoulder and maybe it gives you overhead on rare occasions.
> Let me be clear, C++ is a great language but I fully concur that it takes great skill and resolve to consistently navigate about the landmines you allude to.
Agreed 100%. However I think to navigate some of those landmines you can't get rid of them, you just have to walk around them.
> (though I don't agree UB is non-existent outside of `unsafe`)
I agree that it's not non-existent however the UB outside `unsafe` is assumed to be a bug in the language that needs to either be fixed or formalised as defined behavior.
> ...
I think if you successfully navigate all of the landmines, C++ RAII can outperform Rust where Rust falls short and generally otherwise go toe-to-toe with Rust. However I think Rust gives you most if not all of that overhead reduction for a massively lower cost than C++ for the same benefit.
- AshamedCaptain 3y agoThis talk is just clickbaity, the complains are valid, but to then go and use it to claim that you can never have zero cost abstractions is just .... For example, the ABI used by Linux already passes many structs in registers. Fixing it to also include unique_ptr will indeed "break every aspect of the C++ ABI", but that is not really an unsurmountable problem: Windows breaks C++ ABI on almost every other release (and so does almost any language other than C), Linux user-space has done so in the past, and Linux the kernel just doesn't care. There is no overhead with exceptions when there are no exceptions (e.g., in the kernel). Also think about what it means for the compiler to need to generate exception code: if you were not using unique_ptr, wouldn't you have to make a conditional and free the pointer by hand in such scenario? If the answer is 'yes', then it is not really 'overhead'. > It's only really zero overhead when you can't transfer ownership (`unique_ptr<T> const &`) I think you have this backwards. Pass-by-value can be zero overhead (as in, you can probably think of an ABI which makes it zero overhead and is compliant). It is precisely pass-by-const-reference that cannot be zero overhead, because according to the language rules you are passing a reference to a unique_ptr (i.e. a pointer to a pointer). I'd hardly call that a hidden landmine, as that's what the & means, and I think the average C++ developer is familiar with the concept. Then again, why would you try to pass a unique_ptr by reference is over me. There is really no ownership transfer whatsoever, you are just contaminating your API with unique_ptr unnecessarily. In fact, most of the overheads mentioned just go away if you don't use unique_ptr in function signatures, which is hardly unmanageable mental complexity. In fact, in the proposal here by the Linux kernel, you also cannot pass unique_ptrs through functions; they are type erased.
- menaerus 3y ago> For example, the ABI used by Linux already passes structs in registers It's a bit more nuanced I think - what I understood from that talk is that the "overhead" of a unique_ptr is attached to the inability for a compiler to pass the unique_ptr as a value through a register but will instead have to use the stack (memory). That said, this nuance of using stack instead of registers doesn't apply in the general case but _only_ for the unique_ptrs holding an object with non-trivial copy-constructors or non-trivial destructors - so, non-PODs. If we accept this nuance as a measurable cost in actual workloads where it really matters, this is again only the artifact of Itanium ABI and something C++ can only adhere to but cannot change. Any language that speaks to the system (OS) must do the same. That said, among many other and much more complex code transformations that we do I can hardly see using push/pop instructions as a bottleneck - our CPUs indeed implement push/pop (micro)instructions through a dedicated HW circuitry meaning that they're always on the fastpath and we don't pay the price for them as we do for "regular" instructions. This is why I call this talk a BS and I see it only as a way how Google wanted to prove that "break the world" is worthy under the disguise of zero-cost abstractions that are only "sometimes" zero because of "C++/ABI".