This doesn't match my experience. It's true that modern C++ discourages owning raw pointers, but the solution is usually unique_ptr, not shared_ptr. Truly shared ownership is actually pretty uncommon IME, usually you can have one entity which obviously "owns" the object and then any other reference to it can be non-owning.
It's also worth noting that with std::move, actually changing the refcount of a share_ptr can be pretty rare even if you do have shared ownership.
Tbh, Back then, I didn't see a problem with it. Once i started chasing down weird bugs where objects aren't freed properly because no one knew which objects own what, I have been very cautious.
Sometimes you C++ guys are just blinded by the tale of "zero-cost abstractions".
unique_ptr, like the idea of RAII in general, binds together what should be separate. Data schemas and physical layout on the one hand, and memory and lifetime management on the other hand. What you get as a result is what you deserve: The idea of "more safe and maintainable" where the "more" isn't added to the equivalent non-RAII program. No, it is added to the more convoluted, less understandable, and thus inherently less safe and maintainable program. Who knows what the bottom line is (in my experience often safety is a bit better but I pray for you if you need to debug a problem, and maintainability is much worse), but out of interest in my own sanity I know my preference.
How are they separate? Like, that’s what Rust does pretty explicitly, with great results.
It's like the classic argument against using exceptions: compared with the traditional C method of completely ignoring error conditions and not checking status, they're much slower.
One wart of unique_ptr (and other smart pointers) is that it cannot be passed in a register when used as a function parameter, at least with the System V ABI used on Linux.
Also, the caller is responsible for destruction and there is no way to specify that a function always "consumes" a unique_ptr so the compiler cannot eliminate the destructor code: https://godbolt.org/z/sz79GoETv
Of course if the compiler can inline the call or at least controls both and can clone the function with a custom calling convention then that doesn't have to be a problem. But it still sucks that even something as seemingly simple as a tiny wrapper around a pointer does come with a cost.
As a C programmer, I try to avoid tracking ownership in separate struct member fields. I try to make central data structures that keep care of the tracking. Cleaning up shouldn't happen pointer-by-pointer. Usually a much bigger context has a shared lifetime, so there is no point in splitting stuff up in individually tracked "objects". Instead you just track a bigger block of memory.
Do you mean in terms of cache locality because it's heap-allocated instead of stack-allocated, or are you actually commenting on the overhead of copying some extra ints and invoking the destructor?
Because it's certainly correct that just because you can use a unique_ptr, doesn't mean you should. ("A std::unique_ptr is used for expressing transfer of ownership. If you never pass ownership elsewhere, the std::unique_ptr abstraction is rarely necessary or appropriate." - https://abseil.io/tips/187)
As an added bonus, you don't actually have to do a separate heap allocation.
Since 1993, I never saw any need to keep bothering with C other than having it imposed on me, C++ had enough C89 subset on it, if I ever miss coding like C and its warts.
Nowadays that compatibility is up to C11 subset.
Not true unfortunately, the "C subset" is still stuck at something that can at best be called a fork of "C95" which was then developed into a "bastard language" that resembled C on the surface, but isn't actually C (e.g. the incomplete designated init support in C++20 is the best example of this half-assed "looks like C, but isn't actually C" philosophy).
And C++ has the potential to be faster than C, mostly thanks to metaprogramming (templates, ...). It is horrible if you have to do it, but if you are just using the standard library, you don't have to feel the pain but still take advantage of it. That's how algorithms are implemented. Because so much is known at compile time, optimizers can do a lot.
The reason C++ is generally regarded as slower is that C++ programmers tend to create objects on the heap all the time because constructors and destructors make it easy. Modern C++ also discourages raw pointers and so you get references counters all over the place, essentially turning C++ into a garbage collected language. I am not saying it is bad, but it certainly impacts performance.
But if you manage your memory in C++ just as you do in C, keeping track of all your buffers reusing them, and not using more than necessary, I can easily see C++ beat C.