Orthodox C++
gist.github.com
gist.github.com
> General guideline is: if current year is C++year+5 then it's safe to start selectively using C++year's features.
Sure, I agree, you should carefully evaluate which language best serves your needs, and what tools in a language you should use or stay away from. But some game dev ranting about which C++ features they consider useless (without even articulating their background or constraints) is worthless imo. Especially if this is the credit they give to their name:
> After over 20 years working with C/C++ I finally got clear idea how header files need to be organized.
[1] Yes, that FAQ parody is now very outdated, seeing as it precedes even C++11. I can believe that it was on-point at the time of writing, but C++ grew up since then.
Frankly I haven't used C++ since LLM copilots dropped, so that would address a lot of the tedium with managing headers in rapid greenfield development.
But they have a ton of warts, and require duplicate maintenance.
My hobby C++ coding nowadays only uses modules.
For portable code, I imagine at least 5 years more, given experience with previous C++ standards.
The main issue is that humans suck at defining module boundaries and managing dependencies.
Files are simple.
Thus microservices, nothing like putting process boundaries into what humans fail to learn to do properly, even better with a network in the middle.
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
¯\_(ツ)_/¯I'm fairly sure that all existing C compilers will quietly accept "int main()", but there's an argument that "int main()" causes the program to have undefined behavior. "int main(void)" is the form documented in the standard.
And the "return 0;" is unnecessary both in C++ and in all versions of C starting with C99. (Some will argue that it's better style to be explicit.)
These are admittedly minor points.
Is that really the hello world of c++ though?
It's a bit long in the tooth perhaps, bit I think still highlights some differences between C and C++: "Learning Standard C++ as a New Language":
https://www.stroustrup.com/new_learning.pdf
Ed: I suppose if you want to throw out a lot of c++, then the article might not apply...
import std;
int main()
{
std::println("hello, world");
}
Although your point stands, that is also valid C++.People see some feature X of C++ that they don't like the design or performance of, but .. just don't use it if you don't like it, it's great. People see this setup as complexity, and in a way it is; they're not sure when to use tool X over tool Y over tool Z, what's "modern" and what's "old", but once you're experienced that's what's great about C++. Program with it however you want, for whatever purpose you want, using whichever piece you want. Ignore the stuff you don't like.
The worst part about C++ is that you need to know every other programming language to understand it.
I don't think they're fully known.
Gimme std::vector/map/unordered_map/list. The performance cost is pretty miniscule to not have to worry about which dependency is better. The debuggabilty of those classes is kinda nasty tho.
Measured how? Being good enough or not for which of a million uses? Without that these statements may well be true for the author but meaningless for the reader & potential user.
(Avoiding allocations is frequently a reasonable idea when minimizing latency, for example - maybe not for you).
I think it's wild how people insinuate I'm a fool if I literally say it never is a problem for us. I think it creates a "boy who cried wolf" problem if you always harp on stuff that doesn't actually manifest.
In general, I'm with you on memory allocation. I recently rewrote our animation system to not allocate memory at runtime, but to say "never use std::vector because it's performance is bad" is a statement I can't get behind.
It’s not too bad as long as you have the gdb pretty-printers installed, and explicitly instantiate each of the member functions for each of the template specializations that you use, and link against a debug libstdc++ with bounds checking enabled, and… okay fair point.
I’m so sick of people beating up on C++. The C++ community is in a moral panic to explain why it’s not as safe as rust and coming up with a ten step plan to fix all of the things wrong with it, but the reality is that it’s users like this that give it a bad rep. The same program in idiomatic modern C++ is on average slightly faster than C, significantly safer than C, and usually shorter than C. C++ does not need to apologize for its sins. C++ exceptions are not the end of the world. Templates since C++20 with concepts are ergonomically nicer to use than Java generics (and using them generously can make your code safer), and above all else, it’s a universal language that’s worth investing time in. Mastering C++, or at least attempting to in earnest, will make you a better programmer no matter what language you use for work.
/rant from a C developer that misses C++ every day
I dislike many of the features of C++ and would do them differently, although some things do help. For example, I think that they should not have allowed to overload = and , operators, and I think that features of GNU C such as zero-length arrays and zero-length structures are helpful even though apparently in C++ a structure cannot really have zero length (but in C it can), but my opinion is I think it should be possible for your own structure or union type to overload any operators that are not already defined, including reading through and writing through a pointer (if you define the structure type as having a specific type that it points to; by default it does not point to anything). For example:
struct X x;
struct X y;
(...)
*x=*y; // This line can be overloaded assignment and dereferencing
x=y; // This line cannot be overloaded assignment
x+y; // This line can be overloaded addition, since addition on structure types is not normally definedComma operator I would agree is really only used for shenanigans. But operator= is as crucial as the copy/move constructors for ownership, so I'm not sure how you picture this...
> apparently in C++ a structure cannot really have zero length
Yes it can: https://en.cppreference.com/w/cpp/language/attributes/no_uni...
> I think it should be possible for your own structure or union type to overload any operators that are not already defined
I see that you are trying to solve the problem of "when reading this code, I don't know if these are the built-in operators or custom ones". I would be interested in learning about situations in which this was a problem for you, because I have not made that experience myself. From my perspective, you need to know the types of x and y to know in the first place which operations are possible - default or custom - so this rule does not really buy you much. But again, I don't think I understand your problem well enough.
FWIW, you can define a custom operator-> and operator* (they have to return pointers, or types that themselves have operator->/operator* which are then applied recursively). I am not convinced that mixing pointer-related semantics into e.g. object assignment is a sufficiently elegant solution from a conceptual perspective though.
> Yes it can: https://en.cppreference.com/w/cpp/language/attributes/no_uni...
A structure with no members can be made to have zero length as a member of something else but not as part of its own definition. I.e., the `[[no_unique_address]]` attribute is a property of the member, not of the struct on its own. It's somewhat annoying that you can't flag an empty struct as being really empty, and have no-unique-address-ness applied everywhere it's used automatically; you have to flag every use with the attribute manually.
The only way to enforce this, if you are in full control of the source code you are in - for example the Game Engine / Runtime may fall into this, but it's impossible, or rather impractical to think you can do for the rest of the Game Tools / Plugins / etc.
So with this comes conundrum - folks working predominantly on the Game Engine side tend to push this "orthodox" style as the one that should be accepted, while the folks working on the "tools" style simply can't accept it, because otherwise we have to reinvent tons of code, or not being able to link to closed-source third_party libs in order to make a tool.
It's bananas, and wishful thinking.
Orthodox C++ - https://news.ycombinator.com/item?id=35688013 - April 2023 (3 comments)
Orthodox C++ - https://news.ycombinator.com/item?id=25554018 - Dec 2020 (102 comments)
Orthodox C++ - https://news.ycombinator.com/item?id=13751244 - Feb 2017 (14 comments)
Just to shame one out of this bundle of dumb ideas, the motivations behind avoiding exceptions range from "ugh" to "there's extra code injected in there that might be slow or something." This of course kills RAII patterns and a majority of the advantages of using C++.
IMO, the author should develop a new language and name it C+-, preferably using C preprocessor macros instead of a separate parser.
Having a string abstraction beyond C null-terminated string is a huge deal both for convenience and for safety. It is super easy to get strings wrong in C.
This is also one of the reasons why printf won't work. You cannot pass a type like std::string to a variable args function.
I found it was easiest to sometimes allocate a temporary, if the input wasn't known to be NUL-terminated.
printf("%.*s", static_cast<int>(sv.size()), sv.data())
?Can't you just call .c_str() on the std::string first to get to the null-terminated char array? https://cplusplus.com/reference/string/string/c_str/
std::string str;
printf("%s\n", str.c_str());Too often I have to fix code that makes liberal use of std::string, making copies and allocations everywhere for no apparent reason, when string_view or better const char* would do.
Maybe what we really need is “Catholic C++.”
Actual Amish. Lived on an Amish community near the university.
He never used computers. Always brought a ruler, compass, and protractor to class, which was cool.
Forced us to read Euclid in the original Greek, which was slightly less cool.
The tools were compass, ruler, and protractor.
He started off as a carpenter, but was a mathematical prodigy.
He still saw himself as a carpenter.
What we really need is C2
C with constexpr, type traits, and generics… oh wait this exists! Rust, Zig, etc
Sadly tool chains for some platforms are proprietary variants of llvm clang and fail to include rustc