Doesn't have to be global - could be a member that gets modified in a callback, or that goes out of scope because something else gets deconstructed.
I'd also like to inquire as to what nontrivial codebase you've seen that contains no fairly stupid programming. I keep hearing about them, and trying to prove their existence, but so far I've collected more concrete evidence for the existence of bigfoot than I have for the existence of such codebases.
Other responses (different replies to grandparent) have examples.
More realisticly, if you pass a reference to a different thread and return there is no way when to know when the original goes out of scope. Don't do that.
the whole point of using shared_ptr<T> is to remove the need to "know when the original goes out of scope".
you don't need threads for what you're describing: simply passing it to a same-thread method/function which creates a heap-based copy will already complicate your understanding of the lifetime of the referenced object.
concrete example: we make wide use of the so-called "signals&slots" pattern, which is more accurately denoted as "anonymous callbacks". we have had a consistent source of serious lifetime mgmt problems caused by (boost|sigc|std)::bind()-ing a shared_ptr<T> into the argument list for the callback - the referenced object now lives for as long as the callback itself lives. This isn't explicit in the code, and even today, probably 12-15 years after we first realized the anti-pattern, we still do it from time to time.