Еще одна возможность - это специально созданный умный указатель, который вместо сохранения адреса будет хранить адрес самого вектора вместе с индексом интересующего вас элемента. Затем он соберет их вместе и получит адрес элемента только тогда, когда вы разыменовываете его, что-то вроде этого:
template <class T>
class vec_ptr {
std::vector<T> &v;
size_t index;
public:
vec_ptr(std::vector<T> &v, size_t index) : v(v), index(index) {}
T &operator*() { return v[index]; }
};
Тогда ваш int *ptr=&v[0];
будет заменен чем-то вроде: vec_ptr<int> ptr(v,0);
Пара моментов: во-первых, если вы переставляете элементы в вашем векторе между моментом создания «указателя» и разыменованием его, он больше не будет ссылаться на исходный элемент, а на какой-либо элемент бывает в указанной позиции. Во-вторых, это не проверка диапазона, поэтому (например) попытка использовать элемент 100 th в векторе, который содержит только 50 элементов, приведет к неопределенному поведению.