Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Orthodox C++

Orthodox C++

What is Orthodox C++?

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.

Why not Modern C++?

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).

Why use Orthodox C++?

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.

Hello World in Orthodox C++

#include <stdio.h>

int main()
{
    printf("hello, world\n");
    return 0;
}

What should I use?

  • 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.
  • 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.
  • Don't use metaprogramming excessively for academic masturbation. Use it in moderation, only where necessary, and where it reduces code complexity.

Is it safe to use any of Modern C++ features yet?

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.

Any other similar ideas?

Code examples

πŸ‘

@ghost

ghost commented Jan 16, 2016

Yes please.

oblitum commented Jan 16, 2016

I think you should be more clear regarding "anything that allocates memory". What about "anything that allocates dynamic memory", or memory from the heap, or from free storage. If that is what you mean, maybe you're saying to not use std::array too, regarding memory I mean.

Owner

bkaradzic commented Jan 16, 2016

@oblitum Memory from heap, stack is fine. But it's general because a lot of things allocate memory in STL.

Fixed a typo in the word "adoption" here: https://gist.github.com/elvman/c5b5f081857089ccf695

Owner

bkaradzic commented Jan 17, 2016

@elvman πŸ‘

Great name for this subset! One question: what are the drawbacks to using the C++ runtime wrappers like cstdio and cstdlib?

bullno1 commented Jan 17, 2016

πŸ‘

Owner

bkaradzic commented Jan 17, 2016

@rgthomas It's just a wrapper, it doesn't do anything useful. Just makes C headers pretend to be C++.

Telling people not to use std::vector as general advice (as opposed to on some specific platform, or for some specific performance need) may actually be the worst C++ advice I've seen. It's hard to even imagine how many memory leaks vector has prevented, and how many man hours it's saved.

Streams are not particularly modern C++. They might not even exist if variadics weren't so late to the ball game. Variadic print functions look just like printf, perform similarly, but are much safer: https://github.com/cppformat/cppformat.

features we used proved to be bad (like RTTI, exceptions, and streams),

source ?

Kos commented Jan 17, 2016

Agreeing on a particular representation of "string", "dynamic array" and "associative array" is one of the things I consider to pre-conditions for a mature language.

Why RTTI is bad?

Cygon commented Jan 17, 2016

I respectfully disagree with the extremes to which this idea is taken.

RTTI can be abused (not nearly as much as Java/.NET reflection, though), but it can also be a very neat and tidy puzzle piece that improves performance (see: optionally implemented interfaces!). Exceptions (combined with RAII) are the most efficient and clean error handling method programming languages have come up with so far. STL is useful and well thought out, but okay, even with custom allocators it can be challenging to manage micro-allocations and heap fragmentation on weaker platforms, so perhaps in a few cases roll-your-own is okay.

Source: 20 years of professional C++ development full time (while also trying to keep code maintainable by inexperienced developers)

Just some thoughts.

Don't use anything from STL that allocates memory, unless you don't care about memory management.

What do I use instead? Do I have to make my own container(s)? Why shouldn't I use them? If you're going to say "don't use the STL" at least provide some reasoning and a viable alternative.

If I do roll my own containers, does that mean when I'm going to be using open source libraries there's going to be unnecessary duplicate code just for generic containers because they're not using the STL as you suggested?

Don't use C++ runtime wrapper for C runtime includes (, , etc.), use C runtime instead (<stdio.h>, <math.h>, etc.)

Aren't xxxx.h headers not actually apart of the C++ standard? I thought these were depreciated header files. Maybe I'm wrong, but cppreference doesn't seem to have these documented (only the cxxx.h variants).

Don't use exceptions.

I can understand this from a personal preference, and maybe performance issue if working on embedded devices. But imo, in some situations exceptions could be handy. Though I rarely use them myself.

Don't use RTTI.

Okay, I agree with this. Since there's no standard way for a compiler to implement them, and they are usually a sign of bad design. And if you really do need it, you can easily do it with integers identifying which type it is.

Don't use stream (, , etc.), use printf style functions instead.

Why? I don't see a reason why not to. Other than maybe a "performance reason", but I'm fairly sure printf and streams have similar performance. If anything printf is defiantly less safe, unless you make yourself a safer version using templates.

Owner

bkaradzic commented Jan 17, 2016

@sasmaster It's string based. When you use it, it bloats executable with strings of all classes, and it's slow because does string comparisons.

Owner

bkaradzic commented Jan 17, 2016

@jcelerier Source is personal experience.

Owner

bkaradzic commented Jan 17, 2016

@miguelmartin75

But imo, in some situations exceptions could be handy. Though I rarely use them myself.

Exceptions are not some magic that you enable and your code is just exception safe. Style of code, support to be exception safe, and extra complexity is significant. And not worth for "rarely" used cases.

@bkaradzic The weak exception guarantee is extremely easy to get. You just don't leave unowned resources lying around. Unowned resources for more than a few lines are bad news even without exceptions, it may be fine at the time you commit it but if someone else modifies the code they could easily add an early return that causes a memory leak. Code should be as locally correct as possible; this means immediately taking ownership of resources, and this leads to the weak exception guarantee (which is good enough for many applications).

RTTI isn't super fast, but there are plenty of situations where the performance doesn't matter enough for that to be important. I agree that it's not the first tool you should turn to, but you do occasionally run into things that are awkward to do any other way, where you would likely roll your own version of RTTI if you didn't use regular RTTI. This can be ok too if you can justify the man hours for e.g. performance gain, but often just using RTTI will be easiest and least bug prone.

πŸ‘

Your hello world doesn't show any C++ feature,
So it doesn't show how this is different from pure C.

what is your standing on references ?

Owner

bkaradzic commented Jan 18, 2016

@ chafporte

Your hello world doesn't show any C++ feature,
So it doesn't show how this is different from pure C.

Exactly, that's the point. If you don't need anything from C++ then don't use it, just because you want to be different from C.

what is your standing on references ?

They are fine.

what is your standing on references?

Pointless cruft. They're now useful for making C++ code fit nicely together like a puzzle (different constructors, overloading, operators, templates... etc.) but it would've been better if they didn't got introduced in the language at all.

Amen, brother! πŸ‘ :

mosra commented Jan 18, 2016

Good points, although I have to disagree with this one:

Don't use C++ runtime wrapper for C runtime includes (<cstdio>, <cmath>, etc.), use C runtime instead (<stdio.h>, <math.h>, etc.)

Why would I do that? The C++ includes are not just wrappers, they are converting macro-ridden C insanities into proper inline functions and making them overloaded so you don't have to backtrack your types to use proper abs(), fabs(), llabs() or whatnot. That's in my opinion one of the best features that C++ offers on top of C library. And besides that, I really like the idea of the standard library tools prefixed with std:: to distinguish them from other "non-standard-library" code.

  • Qt

What? Qt? You say that I should not use STL containers because STL containers allocate. That's right, but it is possible to get around many of the allocations with some effort. Qt, on the other hand, allocates all the time and you have absolutely no control about that. I had the "pleasure" of using Qt as a backbone for touchscreen UI running 60 FPS on embedded devices and it's impossible to do anything in it without allocating on every second line. Because of their design decisions like D-pointers and UTF-16, even the tiniest empty objects are allocating and you can't even create a mutex or append a integer to pre-reserved string without spotting tons of mallocs in your profiler. Not to mention the crazy MOC and buildsystem hijacking. Qt is really not something I would put here as an example of well-designed library.

πŸ‘

Owner

bkaradzic commented Jan 19, 2016

@mosra

What? Qt? You say that I should not use STL containers because STL containers allocate.

No, I said if you don't care about precise memory management. Qt is usually used for utilities so memory requirements are a little bit relaxed there.

Qt is really not something I would put here as an example of well-designed library.

It's not example of "well-designed", just example of Orthodox C++ code. I personally think Qt is well designed, the most sane UI framework I used (I used MFC, ATL, wxWidgets, etc.)

Maybe some people can write clang extension to only allow this subset of C++.

My main argument against using STL is the insane amount of code bloat that it generates and its associated increase in compilation time due to excessive use of templates. For example, a simple program that spawns some dummy threads and inserts them into an unordered_set yields an almost 1MB .obj file (VC++2015, Win64, Debug build). In contrast, an object file generated from a 300kb (more than 12000 LOC) C++ source file from RBDOOM3 only has a size of 920KB. Using STL is fine for small applications and tools but when it comes to bigger projects and open source libraries I am against STL, extensive template usage and everything else that bloats the code.

In this Orthodox C++ paradigm can we still use inheritance and virtual functions?

DrCroco commented Oct 7, 2016

I'd say that you're not orthodox enough. First of all, there's no real use for STL. Complicated data structures are never generic, they must be carefully designed for each particular task. From the other hand, primitive data structures, such as vector or list, give almost no profit, but are way harder to debug/maintain than hand-crafted linked lists and resizeable arrays. Furthermore, the very idea of a container class is weird. Container is a thing that contains my data, but a class is a thing I can't (well, must not) look into. So, container classes is when I don't see my data. Hell, I don't want to be blind at the debugging time, as debugging is hard enough without it.

Next, there's no such thing as 'safe features from new standards'. All technical standards since around 1995 or so are simply terrorist acts, and these committees that prepare and create new standards are dangerous international terrorist organizations, and in particular, ISO with their policy of keeping standards secret and selling their texts for money, is the most dangerous terrorist organization in the world, way more dangerous that Al Qaeda. ALL they do is bad. So everything they do must be banned right off, without consideration.

I'm nevertheless glad to see that someone in the world sees the things almost as they are. Modern software industry looks like being made of complete idiots, and there must be some way out of this situation.

Well said! +1000

FrankHB commented Jan 11, 2017 edited

It is suspicious to title things with high density of obvious inconsistency with "orthodox".

For example, the following entries are self-contradict:

Don't use C++ runtime wrapper for C runtime includes (, , etc.), use C runtime instead (<stdio.h>, <math.h>, etc.)
Don't use stream (, , etc.), use printf style functions instead.

How to avoid "stream"? In fact, <stdio.h> provides exactly the APIs for streams. One of them is called the standard (text) output stream, i.e. stdout. And printf relies on it implicitly.

And seems you were allowing <cstddef> (which is hardly a kind of "runtime wrapper") ... huh, is this you want?

And... you forget to rule out <streambuf>, etc...

Some are confusing, like:

Don't use anything from STL that allocates memory, unless you don't care about memory management.

About what? STL was never existed in "modern C++". (You were not meaning Stephan T. Lavavej, right?)

FrankHB commented Jan 11, 2017 edited

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.

I am glad to highly praise such ideas, except you youths are taking it too simple - if you really, really want to "selectively" use the language... And "probably" is hardly enough for tasks in reality once you meet nasty implementation regressions.

Seriously, have you ever done such audit in practice? ... e.g. as the basis, by producing something like this.

FrankHB commented Jan 11, 2017 edited

It's not example of "well-designed", just example of Orthodox C++ code. I personally think Qt is well designed, the most sane UI framework I used (I used MFC, ATL, wxWidgets, etc.)

That's false. Typical "orthodox" Qt-based source is even never a well-formed example for any version of C++. Tools like moc have to be pipelined before feeding the source to any sane C++ implementation, otherwise you'll fail to build. As of non-"orthodox" ones... how do you expect any C++ implementation to be able to translate QML or QSS code successfully?

there's a special kind of hell for you guys

kys

Oh man, I had to use Boost Geometry. I'd been away from C++ for a few years and it make me think my brain had dissolved. I got it to do what it's supposed to - and it did it very well. But, damn, did that hurt.

ahoka commented Feb 28, 2017

Don't tell me what to use.

PhilCK commented Jun 3, 2017

πŸ‘

njlr commented Jun 22, 2017 edited

Hmm... I'm not sure I agree entirely.

Some C++ features that make code more readable and lead to fewer bugs:

  • RAII
  • For-each loops (C++ 11)
  • Smart pointers
  • Templated containers
  • auto

+1 for keeping things simple though.

Words of wisdom! Atleast some in the C++ community realise that, a large number of CPP features are unnecessary or garbage at times. Leaning back to C is ideal in my opinion or in this case orthodox C++ πŸ‘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment