Какое время жизни объекта в std::unique_ptr?
Хотите еще более клевую штуку покажу?int main(int argc, char *argv[])
{
    ttt *t = new ttt();
    t->foo();
    delete t;

    t->foo();

    return 0;
}
Выводит
Alive 0x55d7770d0c20
Removing
Alive 0x55d7770d0c20
( собирал чем попало ).
При вызове деструктора для объекта никто не обязан как-то его "разрушать", скажем занулять область памяти, где он лежал. Это просто договоренность с программистом, что объект удален и обращаться к нему не надо. Что будет если обратиться? Undefined behaviour, частный случай которого мы с вами и наблюдаем.
Уничтоженный unique_ptr уничтожит ваш объект.
«Уничтожит» — это значит, вызовет деструктор и сделает память доступной менеджеру памяти. Теперь другие указатели, которые смотрят на этот объект, будут «висячими», и при их разыменовании программа может сделать ЧТО УГОДНО.
А теперь посмотрим, что именно ей угодно. Ваша функция foo() невиртуальная и не имеет дела с полями, ей нужен только this (указатель на объект), который даже не разыменовывается. Она в принципе не может вылететь, даже если десять раз занулить этот объект!
То, что вы хотите сделать — это семантика std::shared_ptr/weak_ptr.std::shared_ptr<ttt> sh1 = std::make_shared<ttt>();
std::weak_ptr<ttt> we = sh1;
{
  std::shared_ptr<ttt> sh2 = sh1;
  sh1 = nullptr;
}
std::cout << we.expired();  // должно быть true
UPD. Вот для таких, как ты, и ввели в C++14 функцию std::make_unique, по аналогии с std::make_shared. Просто чтобы было меньше таких ошибок.