Approach for one class to safely refer to another, with both having unknown lifetimes
I think using a bit of dynamic allocation std::shared_ptr and std::weak_ptr makes sense as they provide a solid implementation of the tracking behaviour you need.

Your original though has a nice property of not using any dynamic allocation.
If the tracking logic could be refine and made more general if might be a handy bit of library code to have around.

This is my attempt so far:

template &lt;typename T&gt;
class SafeRefTo;

template &lt;typename T&gt;
class Tracked : public T
{
public:
    using T::T;
    ~Tracked();
    void addReferee(SafeRefTo&lt;T&gt; *manager) {safeRefToThis = manager;}
    void markSafeRefInvalid() {safeRefToThis = nullptr;}
private:
    SafeRefTo&lt;T&gt; *safeRefToThis;
};

template &lt;typename T&gt;
class SafeRefTo
{
public:
    template &lt;typename... Args&gt;
    Tracked&lt;T&gt; makeTracked(Args... args)
    {
        Tracked&lt;T&gt; tracked{args...};
        attach(tracked);
        return tracked;
    }

    void attach(Tracked&lt;T&gt; &amp;tracked)
    {
        tracked_ = &amp;tracked;
        tracked_-&gt;addReferee(this);
    }
    void detach()
    {
        if(tracked_ != nullptr)
        {
            tracked_-&gt;markSafeRefInvalid();
            tracked_ = nullptr;
        }
    }
    template &lt;typename TrackedMemFun, typename... Args&gt;
    void invoke(TrackedMemFun fun, Args... args)
    {
        if(tracked_ != nullptr)
            (tracked_-&gt;*fun)(args...);
    }
private:
    Tracked&lt;T&gt; *tracked_;
};

template &lt;typename T&gt;
Tracked&lt;T&gt;::~Tracked()
{
    if(safeRefToThis != nullptr)
        safeRefToThis-&gt;detach();
}


Then the client code is simply:

#include &lt;iostream&gt;

class Actor
{
public:
    Actor() = default;
    Actor(std::string extraText)
    :
    extraText(extraText)
    {}

    void act(unsigned int times) {
        for(; times; --times)
        {
            std::cout &lt;&lt; "hello world!" &lt;&lt; extraText &lt;&lt; "\n";
        }
    }

private:
    std::string extraText;
};

int main()
{
    SafeRefTo&lt;Actor&gt; manager;
    {
        auto tracked(manager.makeTracked());
        manager.invoke(&amp;Actor::act, 1); //output: hello world!
    }//"tracked" goes out of scope: the pointer in "manager" is now invalidated.
    manager.invoke(&amp;Actor::act, 1);
}