4 ms·
C++ certainly has flaws - but it also has intentional design choices, which are important for achieving its goals. Also, as others have mentioned - much has imp
by einpoklum 5y ago
C++ certainly has flaws - but it also has intentional design choices, which are important for achieving its goals. Also, as others have mentioned - much has improved since 2009.
To make this concrete, Let's go over the "C++ defects" summary appearing at the link, before the individual "frequently-questioned answers".
> changing the private members of a class requires recompilation of the code using the class. When the class is used to instantiate member objects of other classes, the rule is of course applied recursively.
This is mandated by two of C++' language design goals:
1. Performance of compiled C++ code: This recompilation is necessary for exploiting optimization opportunities involved the altered private members. In fact, these days, compilers goes beyond even that situation: _linking_ code may trigger partial re-compilation without any changes to the source.
2. Zero-overhead abstractions: Having a private member should not in itself cost you in terms of performance.
However, we can make the class implementation opaque (e.g. using the PIMPL idiom: https://stackoverflow.com/tags/pimpl-idiom/info https://stackoverflow.com/tags/pimpl-idiom/info ) if we want/need to.
> Outstandingly complicated grammar
C++ is guilty as charged here! It even has a semi-idiom named the "most vexing parse": https://en.wikipedia.org/wiki/Most_vexing_parse https://en.wikipedia.org/wiki/Most_vexing_parse
But there is an excuse, which is: Backwards compatibility. First, with C and C's syntax; then, with earlier versions of the language. Fixing the complicated syntax would break all existing C++ versions. So, they don't do it.
> No way to locate definitions
The fix for this is now part of the language: Modules. Unfortunately it will take time before these are widely-enough adopted.
> No run time encapsulation... C and C++ are not designed to run in managed environments
This is again necessitated by the performance requirements. Run-time encapsulation would mean slower code, sometimes much slower.
Also, such encapsulation would mean there would be room for another C++-like language, below C++, without this encapsulation... and a goal of C++ is not to leave such room.
Luckily, in recent years we have undefined behavior sanitizers in compilers, which catch a lot of these cases.
One should also remember that languages with managed runtime environments often have exceptions to the rule, i.e. unsafe/unmanaged sections (unsafe in Rust, JNI in Java).
> No binary implementation rules
Sorry to have to harp on this, but platform-specific ABI is another necessity of performance. Still, C++ has a long way to improve in this respect, e.g. https://stackoverflow.com/q/58339165/1593077 https://stackoverflow.com/q/58339165/1593077
Recently, stack traces have been introduced into the language, and in C++23 they might be available by default when throwing exceptions; see: https://wg21.link/p2370r2 https://wg21.link/p2370r2
(I may continue in another post or extend this one.)
- colonwqbang 5y agoPimpl seems to me like a workaround for deficiencies in the language. It's verbose and inconvenient. We should be able to add private member functions to a class without having to recompile all files that use the class. We should be able to forward-declare a class including public member functions without also declaring the member variables of the class. Even in C I can say: struct A; void public_member_function(A *a); I can also add as many static functions as I like later without affecting the public declararation of struct A. Why not in C++?
- zozbot234 5y agoPIMPL is not a workaround for language-level deficiencies, it's a workaround/pattern for ensuring a forward-compatible ABI.
- ncmncm 5y agoYou may do that in C++, too. It would look, literally, exactly the same. It would compile, and run, identically. And, it would be exactly as error-prone as the same code compiled with a C compiler. Extra support in the language for automating PImpl types could be welcome, but might not offer enough benefit to offset the complexity.
- colonwqbang 5y agoWhy do you feel that it's more error-prone? function(a); vs. a->function(); I can accept that some think the second version looks nicer. But I don't buy that we should have to jump through hoops like pimpl just to get there for non virtual calls.
- ncmncm 5y agoNobody cares how it looks. What matters is that your "a" is a naked pointer. Pointers have reference semantics, not value semantics, so are inherently error-prone. A pointer might be null. A pointer might be already freed. A pointer might be left over from some other use. A PImpl object is a value, with value semantics. It owns the wrapped pointer, and whatever that points at. When it goes out of scope, it cleans up. If you throw, it cleans up. When it is copied, the right thing happens, if that is allowed, or cannot happen, if not. When it is passed to a function, the right thing happens. When it is returned from a function, the right thing happens. The "right thing", in each case, is visible in exactly one place in the source code, and nowhere else. Nothing using it can do any of it wrong. This is all really fundamental stuff.