Reputation:
For example: if I use a variable, which references an element of a vector, and then the capacity of the vector changes, my reference becomes an invalid reference.
#include <vector>
#include <iostream>
std::vector<int> v = {1, 2, 3};
int main() {
int &r = v[0];
std::cout << r << std::endl;
v.reserve(256);
std::cout << r << std::endl;
std::cout << v[0] << std::endl;
}
Any way I can avoid this? Or just don't refer to a vector element?
Upvotes: 5
Views: 218
Reputation: 66371
The robust and minimal solution is to store an index instead of using pointers or references.
You can abstract the indexing out into a type.
Something along these lines (non-template for clarity):
#include <vector>
#include <iostream>
class vector_ref
{
public:
vector_ref(std::vector<int>& v, size_t ix) : m_v(v), m_ix(ix) {}
operator int& () { return m_v[m_ix]; }
int operator=(int x) { m_v[m_ix] = x; return x; }
private:
std::vector<int>& m_v;
size_t m_ix;
};
void foo(int& v) { v = 999; }
int main() {
std::vector<int> v = {1, 2, 3};
vector_ref r(v, 0);
std::cout << r << std::endl;
v.reserve(256);
std::cout << r << std::endl;
r = 21;
std::cout << v[0] << std::endl;
foo(r);
std::cout << v[0] << std::endl;
}
Upvotes: 2
Reputation: 598
If you store objects in your vector as std::unique_ptr or std::shared_ptr, you can get an observing pointer to the underlying object with std::unique_ptr::get() (or a reference if you dereference the smart pointer). This way, even though the memory location of the smart pointer changes upon resizing, the observing pointer points to the same object.
#include <memory>
#include <vector>
#include <iostream>
int main() {
std::vector<std::unique_ptr<std::string>> v;
std::unique_ptr<std::string> s = std::make_unique<std::string>("Hello");
//Use either a reference or a pointer
const std::string* obs_pointer = s.get();
const std::string& ref = *s;
v.push_back(std::move(s));
v.reserve(256);
std::cout << ref;
std::cout << *obs_pointer;
}
Upvotes: 4