Orthodox C++ (sometimes referred as C+) is minimal subset of C++ that improves C, but avoids all unnecessary things from so called Modern C++. It's exactly opposite of what Modern C++ suppose to be.
Back in late 1990 we were also modern-at-the-time C++ hipsters, and we used latest features. We told everyone also they should use those features too. Over time we learned it's unnecesary to use some language features just because they are there, or features we used proved to be bad (like RTTI, exceptions, and streams), or it backfired by unnecessary code complexity. If you think this is nonsense, just wait few more years and you'll hate Modern C++ too ("Why I don't spend time with Modern C++ anymore" archived LinkedIn article).
Code base written with Orthodox C++ limitations will be easer to understand, simpler, and it will build with older compilers. Projects written in Orthodox C++ subset will be more acceptable by other C++ projects because subset used by Orthodox C++ is unlikely to violate adopter's C++ subset preferences.
#include <stdio.h>
int main()
{
printf("hello, world\n");
return 0;
}
- C-like C++ is good start, if code doesn't require more complexity don't add unnecessary C++ complexities. In general case code should be readable to anyone who is familiar with C language.
- Don't do this, the end of "design rationale" in Orthodox C++ should be immedately after "Quite simple, and it is usable. EOF".
- Don't use exceptions.
Exception handling is the only C++ language feature which requires significant support from a complex runtime system, and it's the only C++ feature that has a runtime cost even if you don't use it – sometimes as additional hidden code at every object construction, destruction, and try block entry/exit, and always by limiting what the compiler's optimizer can do, often quite significantly. Yet C++ exception specifications are not enforced at compile time anyway, so you don't even get to know that you didn't forget to handle some error case! And on a stylistic note, the exception style of error handling doesn't mesh very well with the C style of error return codes, which causes a real schism in programming styles because a great deal of C++ code must invariably call down into underlying C libraries.
- Don't use RTTI.
- Don't use C++ runtime wrapper for C runtime includes (
<cstdio>
,<cmath>
, etc.), use C runtime instead (<stdio.h>
,<math.h>
, etc.) - Don't use stream (
<iostream>
,<stringstream>
, etc.), use printf style functions instead. - Don't use anything from STL that allocates memory, unless you don't care about memory management. See CppCon 2015: Andrei Alexandrescu "std::allocator Is to Allocation what std::vector Is to Vexation" talk, and Why many AAA gamedev studios opt out of the STL thread for more info.
- Don't use metaprogramming excessively for academic masturbation. Use it in moderation, only where necessary, and where it reduces code complexity.
- Wary of any features introduced in current standard C++, ideally wait for improvements of those feature in next iteration of standard. Example
constexpr
from C++11 became usable in C++14 (per Jason Turner cppbestpractices.com curator)
Due to lag of adoption of C++ standard by compilers, OS distributions, etc. it's usually not possible to start using new useful language features immediately. General guideline is: if current year is C++year+5 then it's safe to start selectively using C++year's features. For example, if standard is C++11, and current year >= 2016 then it's probably safe. If standard required to compile your code is C++17 and year is 2016 then obviously you're practicing "Resume Driven Development" methodology. If you're doing this for open source project, then you're not creating something others can use.
UPDATE As of January 14th 2022, Orthodox C++ committee approved use of C++17.
- Embedded C++
- Nominal C++
- Sane C++
- Why Your C++ Should Be Simple
- C++, it’s not you. It’s me.
- "Keep It C-mple" Alexander Radchenko Sydney C++ Meetup
- A dialect of C++
- Any C source that compiles with C++ compiler.
- DOOM 3 BFG
- Qt (when built with no-rtti, no-exceptions)
- dear imgui
- bgfx
- TheForge
- Oryol
- Network Next SDK
Uh, I assumed you were complaining about using
std::unique_ptr<T>
in place ofT *
. Of course if one usesstd::unique_ptr<T>
instead of justT
where it's not necessary, then of course that's just stupid, but it's the same as if you were to useT *
everywhere for no reason, really (which is a pattern I happen to see often in C code, btw...). Also, it looks to me likeDictionary
is part of a virtual type hierarchy, which would make it be a lot more logical to use pointers for it (and thusstd::unique_ptr
where appropriate). Of course, you could then complain about inheritance and all things like it, butstd::unique_ptr
can't be blamed for that.Could I get a relevant link to a source on this ? Your description of the problem is extremely vague and I can only vaguely guess what the actual problem they're talking about it (it seems doubtful that they're talking one-line wrapper functions...)
While I can see how some of
std::filesystem
's design leads to security flaws in certain contexts (certainly the lack of a descriptor-based API is a flaw, although not that much avoidable considering how much work it was to get the API we have to be portable everywhere), I don't see the problem withstd::format
in that regard. User-controlled format strings are an obvious problem, and it's pretty much the same as printf in that regard. The OOM vulnerability mentioned in the video you link to later (You seem to have shuffled them up for some reason) is barely anything more than whatprintf
would give you - in factprintf
just straight up gives you the capacity to write to memory with%n
, and it's not gonna be hard to cause a segfault or something like that even if you remove%n
like bionic does.Ah, yes, C++ should completely remove one of their core libraries and immediately replace it with this random other library. This will totally not cause massive backwards compatibility problems...
What do you mean by that ? If you incorrectly use
std::unique_ptr
withstd::default_delete
and that results in the program trying to link to a heap where you can't have one (or can't have a sane default one that works everywhere), then it'll just fail linking. You'll just have to usestd::unique_ptr
correctly as a manager for a non-heap resource.Well of course if you're working within a context where you have several custom heaps you might want to use, then you should just make it so that neither is the default (i.e. don't make
new
be either) and have people manually use the correct one. That doesn't preclude something likestd::unique_ptr
from existing, as long as you set it up to use the correct heap.Yes, and the paper doesn't want to just add them to freestanding, obviously (although it does discuss the possibility of adding it for micro-controllers with perfectly functioning FPUs that just don't otherwise have a full hosted implementation, but it's just a potential suggestion right now)
Why would you need EH to be able to have a usable
std::optional
? A freestanding version can just removestd::optional::value
and that'll be it. People will be able to use it safely withstd::optional::has_value
andstd::optional::operator*
.Same thing for
std::string_view
, just removestd::string_view::at
,std::string_view::copy
,std::string_view::substr
and a few specializations ofstd::string_view::compare
and you've still got a mostly functional version of it (although I do agree it is a bit more limited thanstd::optional
in that regard...)