The rest looks very reasonable, like avoiding locale-hell.
Some of it is likely options that sand rough edges off of the standard lib, which is reasonable.
The rest looks very reasonable, like avoiding locale-hell.
Some of it is likely options that sand rough edges off of the standard lib, which is reasonable.
Yea, you encounter this a lot at companies with very old codebases. Don't use "chrono" because we have our own date/time types that were made before chrono even existed. Don't use standard library containers because we have our own containers that date back to before the STL was even stable.
I wonder how many of these (or the Google style guide rules) would make sense for a project starting today from a blank .cpp file. Probably not many of them.
The STL makes you pay for ABI stability no matter if you want it or not. For some use cases this doesn't matter, and there are some "proven" parts of the STL that need a lot of justification for substitution, yada yada std::vector and std::string.
But it's not uncommon to see unordered_map substituted with, say, sparsehash or robin_map, and in C++ libraries creating interfaces that allow for API-compatible alternatives to use of the STL is considered polite, if not necessarily ubiquitous.
I know, I know, long run does not exists in today's investor dominated scenarios. Code modernization is a fairytale. So far I seen no exception in my limited set of experiences (but with various codebases going back to the early 90's with patchy upgrades here and there, looking like and old coat fixed many many times with diverse size of patches of various materials and colour).
There are cases, however, when the migration costs are significant enough that even those benefits aren't really enough. Migrating our date/time stuff to <chrono> seemed like one of those.
Flashback to last job. Wrote their own containers. Opaque.
You ask for an item from it, you get back a void pointer. It's a pointer to the item. You ask for the previous, or the next, and you give back that void pointer (because it then goes through the data to find that one again, to know from where you want the next or previous) and get a different void pointer. No random access. You had to start with the special function which would give you the first item and go from there.
They screwed up the end, or the beginning, depending on what you were doing, so you wouldn't get back a null pointer if there was no next or previous. You had to separately check for that.
It was called an iterator, but it wasn't an iterator; an iterator is something for iterating over containers, but it didn't have actual iterators either.
When I opened it up, inside there was an actual container. Templated, so you could choose the real inside container. The default was a QList (as in Qt 4.7.4). The million line codebase contained no other uses; it was always just the default. They took a QList, and wrapped it inside a machine that only dealt in void pointers and stripped away almost all functionality, safety and ability to use std::algorithm
I suspect but cannot prove that the person who did this was a heavy C programmer in the 1980s. I do not know but suspect that this person first encountered variable data type containers that did this sort of thing (a search for "generic linked list in C" gives some ideas, for example) and when they had to move on to C++, learned just enough C++ to recreate what they were used to. And then made it the fundamental container class in millions of lines of code.
That's scarier than the containter craziness you mention
That also depends on how standalone the project is. Self-contained projects may be better off with depending on standard library and popular third-party libraries, but if a project integrates with other internal components, it's better to stick to internal libraries, as they likely have workarounds and special functionality specific to the company and its development workflow.
The specification over-specifies std::unordered_map so that no good modern hash table type could implement this specification, but then under-specifies std::deque so that the MSVC std::deque is basically useless in practice. It requires (really, in the standard) that std::vector<bool> is a bitset, even though that makes no sense. It sometimes feels as though nobody on WG21 has any idea what they're doing, which is wild.
for one, its iterator won't be invalidated
It's an adaptor which will use two other containers (typically std::vector) to manage the sorted keys and their associated values. The keys are sorted and their values are stored in the corresponding position in their own separate std::vector. If you already have sorted data or close enough then this type can be created almost for free yet it has similar affordances to std::map - if you don't it's likely you will find the performance unacceptable.
Some notable exceptions: we'd have allowed std::shared_ptr<T> and <chrono>. We might also have allowed <thread> and friends.
> Use char and unprefixed character literals. Non-UTF-8 encodings are rare enough in Chromium that the value of distinguishing them at the type level is low, and char8_t* is not interconvertible with char* (what ~all Chromium, STL, and platform-specific APIs use), so using u8 prefixes would obligate us to insert casts everywhere. If you want to declare at a type level that a block of data is string-like and not an arbitrary binary blob, prefer std::string[_view] over char*.
If your codebase has those guarantees, go ahead and use it.
ISO/IEC 9899:2024 section 7.30
> char8_t which is an unsigned integer type used for 8-bit characters and is the same type as unsigned char;
Because "it supports Unicode" is not an expected use case for a non-8-bit DSP?
Do you have a link to a single one that does support it?
Texas Instruments' compiler seems to be celebrating C++14 support: https://www.ti.com/tool/C6000-CGT
CrossCore Embedded Studio apparently supports C++11 if you pass a switch in requesting it, though this FAQ answer suggests the underlying standard library is still C++03: https://ez.analog.com/dsp/software-and-development-tools/cce...
Everything I've found CodeWarrior related suggests that it is C++03-only: https://community.nxp.com/pwmxy87654/attachments/pwmxy87654/...
Aside from that, from what I can tell, those esoteric architectures are being phased out in lieu of running DSP workloads on Cortex-M, which is just ARM.
I'd love it if someone who was more familiar with DSP workloads would chime in, but it really does seem that trying to be the language for all possible and potential architectures might not be the right play for C++ in 202x.
Besides, it's not like those old standards or compilers are going anywhere.
Portability was always a selling point of C++. I'd personaly advise those who find it uncomfortable, to choose a different PL, perhaps Rust.
Judging by the lack of modern C++ in these crufty embedded compilers, maybe modern C++ is throwing too much good effort after bad. C++03 isn't going away, and it's not like these compilers always stuck to the standard anyway in terms of runtime type information, exceptions, and full template support.
Besides, I would argue that the selling point of C++ wasn't portability per se, but the fact that it was largely compatible with existing C codebases. It was embrace, extend, extinguish in language form.
Being conservative with features and deliberately not implementing them are two different thing. Some embedded compilers go through certification, to be allowed to be used producing mission critical software. Chasing features is prohibitively expensive, for no obvious benefit. I'd bet in 2030s most embedded compiler would support C++ 14 or even 17. Good enough for me.
There is no version of the C++ standard that lacks features like exceptions, RTTI, and fully functional templates.
If the compiler isn't implementing all of a particular standard then it's not standard C++. If an implementation has no interest in standard C++, why give those implementations a seat at the table in the first place? Those implementations can continue on with their C++ fork without mandating requirements to anyone else.
C++ have historically been driven by practicalities, and violated standards on regular basis, when it deemed useful.
> Those implementations can continue on with their C++ fork without mandating requirements to anyone else.
Then they will diverge too much, like it happened with countless number of other languages, like Lisp.
Forgive me if I am unconvinced that the existence of DSP-friendly dialects of C++ will cause the kinds of language fracturing that befell Lisp.
DSP workloads are relatively rare compared to the other kinds of workloads C++ is tasked with, and even in those instances a lot of DSP work is starting to be done on more traditional architectures like ARM Cortex-M.
But for those devices you use limited subset of language features and you would be better of not linking c++ stdlib and even c stdlib at all (so junior developers don't have space for doing stupid things ;))
Back when I worked in the embedded space, chips like ZSP were around that used 16-bit bytes. I am twenty years out of date on that space though.
Anyway, I think there are two takeaways:
1. There probably do exist non-8-bit-byte architectures targeted by compilers that provide support for at-least-somewhat-recent C++ versions
2. Such cases are certainly rare
Where that leaves things, in terms of what the C++ standard should specify, I don't know. IIRC JF Bastien or one of the other Apple folks that's driven things like "twos complement is the only integer representation C++ supports" tried to push for "bytes are 8 bits" and got shot down?
The cpp standard explicitly says that it has the same size, typed, signedness and alignment as unsigned char, but its a distinct type. So its pretty useless, and badly named
Have you read the standard? It says: "The result of sizeof applied to any of the narrow character types is 1." Here, "narrow character types" means char and char8_t. So technically they aren't guaranteed to be 8 bits, but they are guaranteed to be one byte.
The poster to whom you have replied has read correctly the standard.
True, but sizeof(char) is defined to be 1. In section 7.6.2.5:
"The result of sizeof applied to any of the narrow character types is 1"
In fact, char and associated types are the only types in the standard where the size is not implementation-defined.
So the only way that a C++ implementation can conform to the standard and have a char type that is not 8 bits is if the size of a byte is not 8 bits. There are historical systems that meet that constraint but no modern systems that I am aware of.
[1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n49...
I suspect if I dug into the archives, I'd find a discussion on cxx@ with some comments about how doing this would result in some esoteric risk. If I was still on the Chrome team I'd go looking and see if it made sense to reraise the issue now; I know we had at least one stable branch security bug this caused.
But instead we get this mess. I guess it's because there's too much Microsoft in the standard and they are the only ones not having UTF-8 everywhere in Windows yet.
But it isn't really needed anyway: I'm using it for UTF-8 (with helper functions for the 1% cases where I need codepoints) and it works fine. But starting with C++20 it's starting to get annoying because I have to reinterpret_cast to the useless u8 versions.
Second, there is also no way to be able to guarantee that a string encodes valid UTF-8, it could just be whatever.
You can still just use std::string to store valid encoded UTF-8, you just have to be a little bit careful. And functions like codepoints_size() are pretty fringe -- unless you're not doing specialized Unicode transformations, it's more typical to just treat strings as opaque byte slices in a typical C++ application.
You can still use it to contain UTF-8 data. It is commonly done.
> I never said always
Yes you totally did. And regarding "add some new methods for which it has to be UTF-8", there is no need at all to add UTF-8 methods to std::string. It would be a bad idea. UTF-8 is not bound to a particular type (or C++ type). It works on _any_ byte sequence.
Good point, so maybe the standard should just add some functions that take std::string_view. Definitely not add a whole new class like std::u8string ...
Unfortunately, casting a char8_t* to char* (and then accessing the data through the char* pointer) is undefined behavior.
The bulk of the restrictions are justified as "Banned in the Google Style Guide."
In turn the Google Style Guide bans most of the features because they can't/won't refactor most of their legacy code to catch up with post C++0x.
So even then these guidelines are just a reflection of making sure things stay safe for upstream and downstream consumers of Google's largely unmaintained codebase.
That's different from an inability to refactor.
The problem is that too many people drank too much koolaid and trying to parrot everything to a letter without understanding the bigger picture.
The best example would be Kubernetes. Employed by many orgs that have 20 devs and 50 services.
Reasonable summary. There's some massive NIH syndrome going on.
Another piece is that a lot of stuff that makes sense in the open source world does not make sense in the context of the giant google3 monorepo with however many billions of lines of code all in one pile.