Thank you, this is an example of '90s-style C++, serving as a nice contrast to modern C++. Nowadays we would write
struct Point {
double x{}, y{}; // zero-initialization
};
int main() {
Point p; // ok, {0.0, 0.0}
...
p = Point{}; // no need for a "reset"
}
It has been literal decades since anyone competent would have made a Point derived with virtuals, or have written so much code to achieve so little. (You might see stuff like that at Google.) You can write bad code in any language, but if you have to do extra work to make bad code, it is not tempting.
I would argue that (i) old-fashioned code is not deliberately going out of your way to write bad code, and (ii) this should, at the very least, trigger a warning from the compiler.
Old-fashioned code is not necessarily bad code, although the example was; but the topic was "modern C++", not "old-fashioned C++".
Anytime you do all the extra work to write old-fashioned code, you have earned the outcome you get. The oldest-fashioned code looks just like C, which you can still write in a C++ program, if you want to. But there is no reasonable temptation to. Good modern code is equally fast, often faster, and more easily written, understood, and maintained.
If I were to try to pick it up again today, I would have to learn "modern C++"[0] incrementally. I would still have some old habits, and they would take time to iron out. My guess is that it would take me at least a year, possibly more, to become fully proficient in "modern C++".
And even then, I'd still expect that I'd occasionally write some C++ in the "old" way. Maybe I'm tired and forget, maybe I'm lazy and want a shortcut. Who knows. The compiler won't save me from my "old C++". It'll be there, warts and footguns and all.
I'd much rather write in a language designed to not have these problems in the first place, and let the compiler catch as many problems as it can.
[0] Whatever "modern C++" means; I suspect current C++ developers can reasonably disagree on the details, as has been the case for the entire history of C++.
Modern C++ is what was in the Boost framework 15 years ago.</troll>
Joke aside, the STL grew in complexity and features to provide more compile-time constructs and to integrate more functional programming aspects.
For example: I've been told many times that in "modern C++" you don't need `new` nor `delete`.
There are smart pointers, std::array, std::optional, const-expressions, you'll find more and more "single-header" libraries (for JSON, an either monad, etc...), even modules[1].
It's like learning a new language. C++11, 14, 17 and 20 are completely different to C++03 while remaining backward compatible (a critical feature for C/C++ languages it seems).
> but the topic was "modern C++", not "old-fashioned C++".
The problem being that there is no definition of “modern” C++, and even less so that would be enforced by compilers.
> Anytime you do all the extra work
There is no extra work to write “old-fashioned” code. Quite the opposite actually; one has to indicate to compilers to accept newer features rather than the opposite.
> Good modern code
This is a very flimsy, handy-wavy concept, that changes drastically from one “best practice” guide to the other.
> The problem being that there is no definition of “modern” C++
When people say this, they almost always mean making heavy use of C++11 (and later) features, defaulting to `unique_ptr` (or `shared_ptr` if it absolutely needs to be passed around), etc.
Also there's a sizeable minority of people who also mean staying on the stack whenever possible. Which, don't get me wrong, is a good thing, but that's been a thing going all the way back to C. I chalk that particular one up to those people having to debug C++ code written by java devs.
ByteJockey refers to value types, and value semantics.
Besides value types' benefits to code comprehension, they often give the optimizer enormously more latitude to operate because it knows there are no stray pointers to the object.
Over-use of std::shared_ptr is called Java Disease. It has been seen to be curable. A value object containing just a std::unique_ptr<Impl> member (often called "Pimpl", pointer-to-implementation) gets most benefits of value semantics, in cases where Impl is bigger than you would want to pass around directly, and stylistically is overwhelmingly better than passing and returning std::unique_ptr.