In my company's embedded and operating system products, you either use C, C and assembly, or just assembly code. We specialize in very competitive measurement instrumentation and the programming is embedded in these devices. The equipment must do the most work, in the smallest and lightest device, with the lowest power requirements, the longest battery life, the least radiated RF, and the smallest bill-of-materials cost, among all the other requirements. Two typical cases: (1) 512 words of code space and 128 bytes of ram; (2) 16k word of code space and 1500 bytes of ram. Not keeping all these concerns in mind will make the difference between having a product which succeeds and having a product no one buys.
We also write custom operating systems.
Regarding C++, we often can't afford templates, if instantiating support for a data type causes functions I don't actually use to be generated and linked (lacking partial template specialization optimization.) I can't afford exception handling, if the compiler still generates defensive code even when I don't use any syntax in my code for them.
How many people using C++ know exactly how the vtable mechanism works? In the face of multiple inheritance? With virtual base objects? How many people how a C++ compiler supports dynamic casts or know what causes the C++ compiler to generate (or not generate) support for it? What mechanism does a C++ compiler use for exception handling? What does it cost? Where? If one stays away from a mechanism, how much of it is still present?
I need to know what is generated simply by reading the code. I can't get that with C++. I can with C.
Take this sequence of code, found as part of some function in some source code file:
.
.
foo ();
String s;
foo ();
.
.
For purposes of discussion, assume this fragment occurs as part of a routine that doesn't use try..catch at all in a source code module that doesn't use try...catch or declare any throws, either. In fact, assume the module was written almost like C code by someone who wasn't thinking about or worrying over exceptions at all. It might even be a C source code file modified slightly to take advantage of a few C++
features, such as the String class.
Also, for purposes here, assume that foo() is an external procedure and that the compiler has a declaration for it, but does not know its definition.
The C++ compiler, being a smart and proper C++ compiler, sees the first call to foo() and can just allow a normal stack unwind to occur if foo() throws an exception. In other words, no extra code is needed at this point to support the unwind process. But once String s has been created, the C++ compiler knows that it must be properly destroyed before an unwind can be allowed if an exception occurs later on. So the second call to foo() is semantically different from the first. If the 2nd call to foo() throws an exception (which it may or may not) in foo(), the compiler must have placed code designed to handle the destruction of String s before letting the usual unwind occur.
Now, the above is a case where a common, garden variety embedded programmer would imagine that the two calls to foo() would take the same time, require the same resources, and otherwise be the same. Most programmers I know would believe and defend that position, even when told that instead of a C compiler it is a C++ compiler looking at the source code. Even the more sensitive thinking programmers who are aware of exception handling, stack unwinding, and so on, would tend to pause for a while when faced with a source file which quite simply contains NO try..catch blocks, no throws, and otherwise completely avoids any use of C++ syntax related to exceptions.
Yet the C++ compiler *must* be aware of the difficulties and *must* generate different code in these cases, where foo() is permitted to generate exceptions. And without an empty throw clause in it's declaration, the C++ compiler must assume that it may.
All this, in a snip of code in a function in a module none of which has any syntax dealing with exceptions at all. You could read that C++ code snippet all day long and not realize that the two calls to foo() generate different code and execute in different times. Unless you know C++ very, very well.
For some areas, not knowing exactly what you are getting will kill your ability to compete or to write an operating system that even works right. It wouldn't surprise me that an operating system writer such as Linus would shun C++ for operating system work.
That said, we do use C++ for those applications that are neither measurement instrumentation nor operating systems. Mainly, for Windows applications; though C# and VB.NET (and some F#) are also very much used there, too. So for embedded and operating system work, only C or assembly code. For Windows, very little C and assembly except in the cases of ring 0 drivers. But lots of C++, C#, and VB.net there.
It just depends on the work to be done.