I think it's quite OK like that. Of course that depends on the use case and your goal.
One thing I would definitely change though is to return only a std::weak_ptr from addListener.
Here a few alternative approaches:
replace the std::vector with
a std::set or std::unordered_set and keep the std::weak_ptr as the "ID", or
a std::list and use the ...
I think this makes sense in terms of STL use. Storing a std::shared_ptr<std::function> is not usually necessary since std::function may own heap allocations internally, but since you return the shared_ptr from addListener it could be passed around. If you never use the returned shared_ptr, you could just store a std::vector<std::function> and ...