But more that there is so much magic and abstractions that it is very hard for a dev to have a clear view of what is going on and what to expect. He has to 'guess' instead of just read the code. For that, I guess that it is similar to the current question of accountability of decisions made with deep learning algorithms.
As an example of my point, I would refer to the 'garbage collection' issues of a language like 'java'. GC will happen at a logically defined point like 'dirty mem > 100m' but from the developer point of view, his logic could suddenly lag unexpectedly in a middle of a simple operation because the GC was triggered by internal magic. It is very hard for a dev to be able to determine the memory usage at different points of the code and so have a certitude of when this operation could happen.
Two languages could hardly be less alike than Java and C++ - the latter is not garbage collected and where destructors are called is completely predictable.
It is more deterministic in C++, but you can still call exit(). (which is even more straightforward than the refcount cycle)
in the specific case of shared_ptr, which are a small part of codebases, if they are even used - for instance an immense amount of C++ GUI programs use Qt which doesn't use shared_ptr-like ownership semantics but instead a tree-of-objects model which does not have this issue. In contrast in Java / C# any object that has a reference to another is at risk.
when I put some object on automatic storage in C++ I do so because I explicitely want it to go away when its scope is left (either by reaching } or through an exception)
It's not really random, but it's quite hard to follow.
(std::shared_ptr should be used only when absolutely required and should be kept under close watch the whole time.)
Should I be alarmed?
If you have a situation where a value needs to be shared between multiple other values, but also the value is trivial enough that it doesn't matter when it's destroyed or what it does when it's destroyed, but also the value is not so trivial that you can copy it instead of using a refcounting pointer, then std::shared_ptr is fine.
Unless you know you must share objects with multiple potential owners, though, std::unique_ptr is a lot wiser.
>but also the value is trivial enough that it doesn't matter when it's destroyed or what it does when it's destroyed"
that precludes the value from having other refcounting pointers that could then create cycles and leak.
There’s a good chance that most of the shared_ptr’s can be replaced by unique_ptr, which has less runtime overhead. More importantly, it documents the intent of the programmer regarding ownership semantics, and the timespan during which the object should be remain valid.