Which features in particular?
One of C++'s core tenants is (and has been since the 90's) zero-cost abstractions. Or really, "zero-runtime-cost abstractions"; compile times tend to increase.
Obviously some abstractions necessarily require more computation (e.g. raw pointers vs reference-counted smart pointers). But in many cases new features (if implemented correctly!) give better semantics and additional compile-time safety while still compiling down to equivalent binary.
So, here's the thing: Officially, C++ is committed to "What you don’t use, you don’t pay for (zero-overhead rule)”. This is item 2.4 in the reaffirmed design goals:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p34...
but the current ABI _forces_ some abstractions to have unnecessary cost. For example:
"Why can a T* be passed in register, but a unique_ptr<T> cannot?" https://stackoverflow.com/q/58339165/1593077
another example is improvements in the implementation of parts of the standard library.
And that is not the only thing that prevents zero-cost abstraction. C++ does not support pointer restrction, see:
https://stackoverflow.com/tags/restrict-qualifier/info
in practice, compilers support it for some contexts.
(Anoter, minor issue is the discrepancy of "No viral annotation" and "no heavy annotation" with the need to mark things noexcept to avoid exceptio handling overhead.)
For unique_ptr: This is not a problem that can be solved by the standards committee, they don't control the SysV / Itanium / Win64 standards. You can still use raw pointers if you want to, nothing has been lost from C.
For restrict: Universally supported as `__restrict`, thus not a priority for anyone to "officially" solve. Most major performance complaints fall into this category. Eg, std::regex is bad, sure, but nobody uses std::regex so fixing it doesn't matter.
> This is not a problem that can be solved by the standards committee
SysV/Itanium/Win64 knows nothing about the abstract difference between a 64-bit value and a 64-bit value inside a class instance. Don't see what prevents the solution from the language side.
> Universally supported as `__restrict`
1. That's not C++. If we're talking about what compilers can offer outside the language standard - that's a different discussion. We don't have to standardize, then, just get a working implementation somewhere and lobby other compiler-makers to adopt it. A compiler might implement Baxter's "safe mode" idea as a non-standard extension, for example.
2. Even the compilers supoorting `__restrict` only support it for parameters of functions - nowhere else.
> Don't see what prevents the solution from the language side.
The standard has nothing to say about calling convention. Calling conventions are defined by the ABI standards. unique_ptr is a class template, how a class is passed between routines is defined by ABI standards, ergo how unique_ptr is passed between routines is defined by the ABI standards. I don't know what else you're implying here. Unless you're saying we should have language-level smart pointers, not class templates, in which case yes that's an awful idea.
> That's not C++...
If you're arguing about some abstract, Platonic ideal of C++ that is divorced from the actual implementations that exist in the world, I don't know what your point is. We write code to be compiled by compilers that exist, not printed out and contemplated in a museum. The compilers support __restrict, people use it all the time, so its not a problem.
> Even the compilers...
Where else do you want it? What would its meaning even be to something like a member variable?
Restrict is pointless in any scenario that doesn't involve a potentially aliasing ABI boundary, ie, function parameters. In every other scenario it is ignored.
> The standard has nothing to say about calling convention. Calling conventions are defined by the ABI standards. unique_ptr is a class template, how a class is passed between routines is defined by ABI standards, ergo how unique_ptr is passed between routines is defined by the ABI standards.
The ABI defines the calling convention but it is restricted by the guarantees the language already makes. Specifically this part from the System V ABI spec quoted in the linked SO discussions:
> If a C++ object has either a non-trivial copy constructor or a non-trivial destructor, it is passed by invisible reference (the object is replaced in the parameter list by a pointer that has class INTEGER).
> An object with either a non-trivial copy constructor or a non-trivial destructor cannot be passed by value because such objects must have well defined addresses. Similar issues apply when returning an object from a function.
What is needed so that we can have smart pointers passed in registers is:
a) A way to specify that the address of the object itself may change (even though the object is not trivially destructible). P1144's [[trivially_relocatable]] would cover this requirement.
b) The System V ABI needs to be adapted to make use of this new information. Note that this also requires to make the callee responsible for destruction which may or may not be desirable generally (makes fusing allocation and deallocation harder or impossible in many cases) - raw pointers leave this decision to the programmer.
c) The standard library needs to add the new attribute to unique_ptr et al. This would now be an ABI break (the goal is to improve the ABI, duh).
So in essence BOTH the language AND the ABI need to be adapted to achieve the optimum behavior here. And even then with only [[trivially_relocatable]] there is still a difference with raw pointers less flexible in which function the destruction happens. And making the ABI depend on [[trivially_relocatable]] limits where the attribute can be added - so the the ABI depends on the the language spec and the standard library spec depends on the ABI for its compatibility requirements.
> The standard has nothing to say about calling convention.
If the ABI refers to the standard, the standard can constrain/manipulate the ABI. Specifically, the standard could say destructors and copy ctors must, under certain conditions, be considered trivial for ABI purposes.
But really, account42 has it right when he talks about co-changes to the language and the ABI - that's the better way to think about it.
> I don't know what else you're implying here.
You're feigning ignorance. I said what I implied.
> Where else do you want it?
In struct fields of course. (Also the corner case of restriction of the "this" pointer, but that could arguably be covered by function parameters + fields)