const int MIN_CAPACITY = 16;
const int GROWTH_FACTOR = 2;
const int SHRINK_FACTOR = 4;
these should be part of the class, not global variables that affect everything and pollute the namespace when your header is included.
And use constexpr now.
_data(new T[MIN_CAPACITY]
No naked new!
Use a unique_ptr<T[]> instead of a bare pointer for _data.
T *tmp = _data;
_data = new T[_capacity];
std::copy(tmp, tmp+_size, _data);
delete [] tmp;
again, using a unique_ptr you won't need to delete manually.
But rather than copying the old vector, you want to move the elements. Consider if T is something that is expensive to copy (like a string) or cannot be duplicated!
I suspect the same for insert and delete as well. Test it with T that has a deleted copy constructor and assignment operators, but does have a move constructor.
For testing, try the "Catch2" library: