Yes, definitively! Using shared pointers can hide bad design.
There are some cases when it is hard to choose the owner of data. Two examples come to my mind. The first are directed graphs: what owns nodes? The second example are parsers, sometimes AST subgraphs must be assigned to extra structures during further processing (type analysis, code generation and so on).
Last time I used shared_ptr in my code was for a 3D authoring app. Users can load/copy/paste 3D objects, I want a single copy on RAM and VRAM for clones of the same 3D object. If you ask me “why” — because VRAM is limited, and because PCIe bandwidth is a bottleneck.
I‘ve decided that scene node is the true owner of the mesh, and placed shared_ptr<mesh> in my scene node class.
Technically, I could instead decide that scene (i.e. “the graph”) is the true owner of all the meshes in all graph nodes, as you’re saying. Two problems:
1. I would write my own code for memory management and reference counting, for no good reason replacing a perfectly good standard library implementation.
2. Scene is not one true owner that manages the memory of the meshes because of different lifetimes. Users can add/remove stuff from the scene. When they do, both scene nodes and meshes are allocated/deallocated. When two objects are allocated + deallocated together, it’s often a telltale sign that one of them is the true owner of another one. The scene itself lives much longer.
Every object should have one true owner that manages its memory. Anything else will lead to performance regressions and outright bugs.