user2269707
user2269707

Reputation:

Any way to update pointer/reference value when vector changes capacity?

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

Answers (2)

molbdnilo
molbdnilo

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

NotAProgrammer
NotAProgrammer

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

Related Questions