That was Stroustrups reasoning: "Only pay the cost when you use it". In retrospect, believe that that's a bad choice for language design, because there's a good chance somebody will use a feature without fully understanding the ramifications it has over the entire code base.
C opts for the opposite and uses annotation to treat certain code segments as "special" and make them faster - "inline", and (in the distant past) "register" come to mind.
(or at least the cons)
I believe I do get the pros as well, at least to some extent. I've been using it since CFront came out ;) And I'd still advocate it for use in a small team (<5 people?) of experienced programmers - you can make it sing.
But gamedev engineering teams are at least 15+ people, with the occasionally less-experienced ones thrown into the mix. C++ is, in a sense, like a professional power tool. It sure can get stuff done, but the wrong person uses it and its a blood bath, and it's not appropriate for single small home repairs. (Gah. Bad analogy, but I can't come up with a better one right now)
This is just bad programming practice on their part. The performance cost of a destructor shouldn't be a surprise to the person who writes it
Possibly. I'd argue that it's hard to always keep all performance ramifications in mind. But let's for a moment say it's indeed simply bad programming practice - the issue that makes this a problem is that my code pays the cost, not the offending code. Which is a rather indirect.
C++ changes often have tendrils all through the system. It is easy to make inadvertent mistakes.
* but it is definitely "decent" in the sense of "adequate.*
It clearly gets the job done, yes. We are shipping games occasionally, after all. I'm looking for better ways to ship games, and I think that abandoning C++ might bring gains.
The second problem with C++ is that it's extremely complicated and takes a long time to learn.
That's what my hidden cost is referring to - C++'s complexity makes it hard to understand. You certainly can write code that performs well in C++, but it is arguably harder to get it right than C.
I like to think there's a better solution than either one hiding somewhere, but I haven't found it yet.
The issue is that in many instances, I own the caller, but not the callee. And the person owning the callee can unintentionally make my code perform worse by simply changing the API. Or adding a destructor.
This is just bad programming practice on their part. The performance cost of a destructor shouldn't be a surprise to the person who writes it. If someone is messing with the performance of types you use or removing functions(+) you call without consulting you and without themselves taking responsibility for calls to that functionality, then obscure features of C++ is just one of the many ways they're going to screw you on a regular basis. How would those programmers screw you in C? I don't know, but I know they would.
Nobody who knows C++ well enough to use it effectively would call it a "decent" language in the sense of "not obscene," but it is definitely "decent" in the sense of "adequate." It's easiest to define C++'s deficiencies with respect to other languages (for instance, memory management in C++ is much more intrusive in source code than in Java) but comparing it to C is way too simple. After all, the primary problem with C++ is that it doesn't remove any of C's dangers; it just gives you better ways of abstracting them away in some cases. The second problem with C++ is that it's extremely complicated and takes a long time to learn. And that's it. Every other supposed misfeature of C++ (relative to C) seems to stem from people hitting the second problem without realizing it. In your case, your coworkers should be more conservative about messing with things (such as defining expensive automatic type conversion functions) when they don't understand the consequences (such as those type conversions actually being invoked.)
(+) This is the most plausible explanation for different type conversions suddenly being invoked. It could also happen by adding a function that invokes a more expensive type conversion to a type that is more closely related to the type declared by the caller, thus making the new function a better match than the old one, but it's unlikely that a conversion between two types that are more closely related would actually be more expensive.