I'm making the assumption that Engine::object is a std::map type, with a std::string as the key, and a std::vector of "base object pointers" representing objects of the type that corresponds with the key.
If that's the case, Engine::DestroyObject is almost certainly wrong. Anytime you use operator on a map and the key ("Bullet" in this case) doesn't exist, the key is added to the map, so object.at("Bullet") will never fail. It is entirely possible, however that the vector associated with that key is empty in which case invoking erase on it is likely to result in an out of range exception. Also, Engine::DestroyObject erases the only the first item in the vector. This is important.
The for loop suffers from a different problem. You iterate through the vector associated with the key "Bullet", updating y values of those objects and if the y value exceeds a certain threshold, you want to delete that item from the vector. But, you don't. What you actually do is call Engine::DestroyObject which erases the first item in the vector, not the item you actually wanted to remove (unless, by coincidence, it happened to be the first item in the vector.) Now, when you erase an item in a vector it also invalidates all iterators that point to that item or any items that occurred after it in the vector. Since you're erasing the first element, you invalidate all iterators into the vector.
Your range-based for loop was using an iterator into the vector. That iterator is invalid, but it continues to be used as if it wasn't.