Re: c++ const nightmare, specially used in pointers.
Posted: Sun Nov 18, 2018 5:41 pm
Switching to a newer version of the language standard is a modification of the code. At which point you have to make these modifications anyway; no matter if it's C99->C11 or C++98->C++11. If you stick to the old standard, there's no "namespace encroachment". If you switch to the new standard, you should be moving things out of the way that collide with new features no matter what. Having your own defines for "bool" and "true" and "false" was fine with C98, but with C99 you better replace them with <stdbool.h>.nullplan wrote:If you're paying attention, you will notice that, with the exception of inline and restrict, all of these begin with an underscore and a capital letter (unless a hitherto unknown header file is included). However, names that start with underscore and capital letter (or two underscores) are defined to be reserved for the implementation. And therefore, conforming programs could not have used these new keywords before. Therefore old programs remain compilable with new compilers, unless the code is modified to include new header files, in which case the code is already being altered, so you might as well rename the struct fields or whatever is clashing.
At which point it doesn't matter that the keywords are from the reserved namespace; you should move your code to not collide with the convenience macros anyway. Because if you state your code compiles with C99 / C11, it should do so even if someone adds "#include <stdbool.h>" or "#include <stdalign>".
At which point the workload of updating C99->C11 is comparable to e.g. C++98->C++11.
The effort implied in making the step from C -> C++ is not what was being discussed in this bullet point; it was about the workload induced through "namespace encroachment" by coming updates to the standard. And I think I showed that C++ isn't any worse than C here.nullplan wrote:And let's not forget that even in C++98, there are keywords that were not present in C89, especially "class". You don't know how often a variable named "class" might come up until you try to compile C programs as C++.
std::string is a class of the standard library, last time I looked. And if you wrote your function to expect a std::string, obviously you expected such a string object to come into existence, didn't you? So it's hardly the fault of the caller when indeed it does...nullplan wrote:So they don't, do they? Why then are so many talks at CppCon about "how many memory allocations happen in this snippet?" You pass a string literal to a function expection a std::string, you get a temporary. That is an allocation (and a free afterwards, thus contributing to fragmentation) that is not explicitly requested.Solar wrote:Neither the compiler nor the language do hide memory allocations. A couple of the classes in the standard library do.
And if your string is short enough to get by without dynamic memory allocation -- 22 characters plus terminator -- SSO makes it so...
(Also be careful about what you call a string literal -- "foo"s is, "foo" isn't -- and double-check on what actually does imply a temporary including constructor call and what doesn't. Anyway, your function should take a std::string reference... at which point most of the temporaries you might think of vanish. )
You write a kernel default allocator class that calls a handler or something instead of throwing std::bad_alloc. Not strictly standard-compliant, but very few things in kernel space are.nullplan wrote:And besides, what do you do in a no-exception environment if allocation fails?
By the way, while we're on the subject of memory allocation failure... scan the Linux kernel source for calls to krealloc() if you're bored some day. About one in ten calls assigns the return pointer directly to the current pointer variable. Unless krealloc() does something fundamentally different to standard realloc(), those pieces of code won't handle memory exhaustion that gracefully either, do they? (Just something that caught my eye in passing when I did some checks while writing that last post; perhaps those cases are "cannotreach" or something, but I had to grin at that obvious code smell.)
-Wconversion, explicit, ...nullplan wrote:C++ hides a great many things from you (constructor calls for static objects, constructor calls for implicit conversions...
The basic idea being, that the operator does the right thing for the object it is applied to. If I'm passing void * around in structures I'm expecting the receiving functions to do the right thing on those as well. Only that the compiler cannot even check that and has to take it on blind faith that data and operation match.nullplan wrote:...which of these operators is actually an overload...
Neither is C.nullplan wrote:Good programmers can write FORTRAN in any language, and C++ is no exception.
Actually, it doesn't. If you disable RTTI and exception handling, the runtime requirements of C++ are identical to those of C. Been there, tried that for Pro-POS "Foundation", as far as we got with that. (Which was not very far indeed, but we had the bare bones console I/O with classes and operator<<() and everything.)nullplan wrote:My personal argument against C++ in kernel space is actually this: C requires far less runtime support. You set the environment to freestanding, define memcpy() and memset() (as ordained by the GCC high priests *sigh*) and you're basically done. Everything else you write, you write the way you want. The entry points have to be written in assembly, anyway. C++ has a freestanding environment as well, it just requires a lot more.
Edit: Caveat -- you need to call any non-trivial constructors for global objects, I had forgotten about that. Not too difficult though, just get the array from the linker and call each of the functions pointed to.