They have a bit different if you use https://godbolt.org/ to check
by using gcc(7.2)
foo.reset();
generates assembly code
lea rax, [rbp-32]
mov rdi, rax
call std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::reset()
however,
foo = nullptr;
generates
lea rax, [rbp-16]
mov esi, 0
mov rdi, rax
call std::shared_ptr<int>::shared_ptr(decltype(nullptr))
lea rdx, [rbp-16]
lea rax, [rbp-32]
mov rsi, rdx
mov rdi, rax
call std::shared_ptr<int>::operator=(std::shared_ptr<int>&&)
lea rax, [rbp-16]
mov rdi, rax
call std::shared_ptr<int>::~shared_ptr()
It creates a shared pointer with nullptr, assign the newly created object to the variable and calls destructor to destory string.
Since I don't know how to check what happened in the function reset(). Can not see which is faster.