Shared pointers are meant to prevent access of deleted objects, by ensuring they aren't deleted while references to the object still exist. I fail to see how I am still running that risk while using shared pointers (given that I don't stupidly delete the object manually).
>> Is this a situation where it would be best not to use smart pointers, and have the risk of
>> the user dereferencing an invalid pointer?
At worst, you run the same risk when using the smart pointer, you don't run any greater risk. Using the shared_ptr gives you an opportunity to manage the hierarchy through weak_ptrs, so there is a benefit there.
Sure, if the user no longer holds any references to the Entity, it will be deleted. If they do, the Entity will still exist, but will no longer function correctly due to the deleted Root. SubEntity needs Entity and Root to function correctly. Another possibility would be for Root to notify all Entities of its deletion, which would in turn notify all SubEntities, removing the need to check weak_ptrs every time. This is a bit of a contrived example, but it demonstrates my situation well (I think :P).
>> if Root is destroyed, the Entities will still exist
I'm confused about this part, though. If Root is destroyed, and it is the only object holding a shared_ptr that owns the Entities (with other objects holding weak_ptrs), then the Entities will be destroyed right then, correct? That means that the SubEntities will be destroyed as well assuming they follow the same pattern. All weak_ptrs referring to the Entities and SubEntities will still exist, but there would be no need to check the entire chain, right?