7 ms·
> It is easy to see that C++ is fit as a general-purpose programming language–adoption by millions is a testament to that. I really wish the std would drop thi
by CoolGuySteve 3y ago
> It is easy to see that C++ is fit as a general-purpose programming language–adoption by millions is a testament to that.
I really wish the std would drop this pretense and focus on C++'s strong point: Continue being the fastest systems language possible.
Everywhere in the std lib you can see compromises that require rewriting substantial portions for any real time application.
Things like: shared_ptr eagerly using atomics whenever possible; std::string allocating; the lack of built-in faster std::allocator replacements like bump allocators, memory pools, etc; no lockless and wait free concurrency primitives; no architecture-aware thread pools or even architecture descriptions; no IPC primitives; etc.
Considering how many C++ developers are working on things like games, high performance server applications, databases, and operating systems, it's just bizarre how inappropriate the standard headers are for these tasks.
Even something trivial like casting bytes off the wire to a packed struct is an exercise in frustration due to aliasing rules that should have been encoded in the type system and invisible to the user.
- zozbot234 3y agoWhy does this have to be part of the standard library? Isn't that the whole point of Boost, that one is not limited to what's in std?
- CoolGuySteve 3y agoIt depends on the contributors, but boost also almost always fails to consider performance implications. For me it mostly looks like a reject pile for a stdlib that I must also reject most of the time. The alignment of incentives between these library authors and people that use C++ for high performance applications is just off.
- gumby 3y ago> For me it mostly looks like a reject pile for a stdlib that I must also reject most of the time. It’s also the opposite: a place where possible candidates for the standard get tried out first. But like you, I rarely use it.
- andrewmcwatters 3y agoI have never once seen Boost seriously considered in performance environments.
- Kranar 3y agoBoost has its uses and in many cases it's an improvement over the standard library, but performance isn't one of its key properties. Some parts of boost are about as fast as they can be, but that's the exception.
- menaerus 3y agoEven if somebody put such a thing, or two, in the standard library there would be again someone showing that they managed to come up with a better solution. For their workload. And under constraints that are only valid under their use-case and constraints that only they would know. Not standard library developers. And that's the thing - the premise that "one size fits all" even exists is wrong. I used to think that way as well but generic solutions to high-performance algorithms do not really exist.
- shortrounddev2 3y agoIt was my understanding that one can easily add their own allocator to any STL container, though as you point out you have to write that allocator yourself
- worik 3y ago> one can easily add their own allocator to any STL container, You and I must have a different definition of "easily "
- menaerus 3y agoHow about this? template<typename T> struct Foo { using value_type = T; Foo() = default; template<typename U> constexpr Foo(const Foo <U>&) noexcept {} T* allocate(std::size_t n) { if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) throw std::bad_array_new_length(); auto p = static_cast<T*>(std::malloc(n * sizeof(T))); if (!p) throw std::bad_alloc(); return p; } void deallocate(T* p, std::size_t n) noexcept { std::free(p); } }; And then you go and use it as std::vector<int, Foo<int>> v; So the complexity is not really in writing the "C++ allocator" but in writing a sufficiently complex memory management logic that will actually make your application/algorithm run faster. And that only you can know given that you're familiar with the memory allocation patterns in your code. C++ allocator is only an interface that allows you to capture that logic and makes it feasible to apply through the code.
- viraptor 3y agoIf you're in a position where you know you need a different allocator, and you have your own allocator, plugging it in should be relatively easy in comparison.
- CoolGuySteve 3y agoYou can but it's definitely not easy to do correctly. There's also a lack of traits that can describe what's required of a specialized allocator. For example, std::map only needs to allocate 1 object at a time in practice while std::vector needs to allocate a contiguous count of objects.
- gavinray 3y ago> Continue being the fastest systems language possible. If you want to be pedantic -- in theory C++ can never be the fastest systems language possible because of the language's rules about aliasing. You'd need to smatter "_restrict" everywhere to skirt this.
- Kranar 3y agoThis is not pedantic at all. Aliasing issues are really subtle and hinder so many optimizations. It's not clear that there is a way to even fix this without substantially breaking backwards compatibility.
- UncleMeat 3y agoYeah the number of cases where otherwise really trivial optimizations are prevented because of soundness concerns regarding aliasing is simply enormous.
- dataangel 3y ago> If you want to be pedantic -- in theory C++ can never be the fastest systems language possible because of the language's rules about aliasing. True but the only practical competitor is Rust, and they gain some alias information (mut) and lose other aliasing information (type punning is fully allowed in unsafe code all the time).
- zozbot234 3y agoNot so, unsafe code still has restrictions in Rust due to pointer provenance. You can override these restrictions but it's very much an explicit operation, the default is that pointers with incompatible provenance will not alias. This is how Rust models its equivalent to TBAA, and the concept is spreading to C/C++ as well.
- dataangel 3y ago> Not so, unsafe code still has restrictions in Rust due to pointer provenance. That's separate from what I'm referring to. In C++ a float* and an int* can never alias. In Rust f32* and u32* are allowed to. Meaning in a situation where whether they can alias can't be established by provenance (e.g. in a separately compiled function where the compiler at compilation time can't tell where the float and int came from) then C++ is able to use types to rule out aliasing, but Rust cannot.
- MaxBarraclough 3y agoYour specific gripes seem reasonable (I suspect design-by-committee plays a big part), but: > I really wish the std would drop this pretense and focus on C++'s strong point: Continue being the fastest systems language possible. You've essentially described C, not C++. C++ has a different philosophy and makes different trade-offs. C++ is at least still pretty committed to the you only pay for what you use principle. As far as I know RTTI is the only real exception (corrections welcome), but even RTTI can be disabled in many compilers. Some of your gripes with the standard library can be addressed with libraries, perhaps from the Boost project.
- gafferongames 3y ago> C++ is at least still pretty committed to the you only pay for what you use principle. As far as I know RTTI is the only real exception (corrections welcome), but even RTTI can be disabled in many compilers. Compile time would also be an exception.
- throwaway81523 3y agoI had a program that had to parse a lot of integers like "12345". The std way to do it was an order of magnitude slower than writing my own simple parsing code. I have no idea what the std version was doing, but it was crazy to see my program's execution time (measured in hours) dominated by int parsing. The handwritten version eliminated that.
- leopoldj 3y agoYou didn't say which std function you were using that was slow. But std::from_chars performs a lot faster than std::stoi et al due to many reasons.
- throwaway81523 3y agoYeah I don't remember what I originally used. It might have been stoi but it might have been iostream.
- GoblinSlayer 3y ago>std::string allocating You mean you want string_view? It still calls strlen when you instantiate it with a literal though.