3

I want to know if there is a way to keep track of addresses of elements in a vector.

I like to use vector of solid elements like std::vector<MyObject> vec because:

  • std::vector do all the allocation / deallocation stuff for me
  • it also ensures me that my elements are stored in contiguous memory
  • I can get benefits of all code that work with vectors (e.g. <algorithm>)

This is exactly what I want. The problem arises when I want to store the address / reference of elements of my vector in other objects. In fact, the problem really arises when std::vector need to reallocate memory.

I tried to find alternatives to my problem:

  • Use vector of pointers / smart pointers : No, the pointers will be allocated contiguously but not the elements

  • Use vector of pointers / smart pointers and write my own operator new/new[] for MyObject : Humm, that seems better but no. By using a vector to allocate my elements I can say : "those particular set (I do not refer here to std::set) of elements must be allocated contiguously, not all". In fact I may want to have other set of elements that should be allocated contiguously because of the way I want to use them and using a vector to do that is exactly what (I think) I need. Thats also implies that I'm doing the job I want the vector to do.

  • Why not using boost multi-index? : In some ways that will do what I want because I want to store pointers/smartpointers of my vector elements in other containers. But no again because I really want to store reference/pointer/smartpointer of my vector's elements inside other objects, not just other containers.

What I would loved to have is a vector that can give me a pointer object that will allways point the the address of the desired element and I will use it like that :

std::vector<MyObject> vec;
// insert some elements
...
// get a pointer object by index or by using an iterator
// does something like that exist?
std::vector<MyObject>::pointer ptr = vec.get_pointer_at(5); 

// do what I want on the vector except removing the element
...

// use my pointer whatever reallocations occurred or not
ptr->doSomething();

That sounds like an iterator that will never be invalidated except the fact I don't need/want to perform arithmetic on it (+x, -x, ++, --).

So, can someone leads me to the way to achieve what I want or explain me why/where I'm wrong wanting to do this? Please accept my apologize for my lack of knowledge in STL if there is a well known solution that I missed / or if this question has already be answered.

Edit:

I think that if I have to code such kind of pointer, that means that I'm wanting something useless or I'm wrong somewhere (unless someone should have already wrote a template for that) . So I'm more looking to a validated C++ idiom to get rid of this problem.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Laurent
  • 812
  • 5
  • 15
  • If you need to change the contents of the vector a lot you will have to change the container. If you only change the contents of the vector but not the size then you should be fine. – RedX Oct 02 '13 at 14:04
  • Laurent, have you considered `deque`? – ArtemGr Oct 02 '13 at 14:06
  • 3
    What about writing an iterator that is not invalidated. Store the index inside the iterator instead of the element's address. – cdoubleplusgood Oct 02 '13 at 14:09
  • @ArtemGr, deques are not guaranteed to store elements in contiguous memory – Laurent Oct 02 '13 at 14:12
  • @cdoubleplusgood, i'm not a big fan of using index values, this prevent from doing insertions (maybe i'm asking too much to the vector) – Laurent Oct 02 '13 at 14:22
  • 1
    I would **strongly** question the need to *store* (ie *retain*) pointers to elements in a `vector`. – John Dibling Oct 02 '13 at 14:29
  • you mean a pointer pointing always to a given element of the vector, or a pointer pointing always to a given position of the vector? (Note in the second case the object pointed by the pointer could change due to vector resizing) – Manu343726 Oct 02 '13 at 14:30
  • @JohnDibling share ownership with elements stored in a vector, without losing one of the advantages of vectors: Contiguous cache-friendly memory. Its a good goal I think – Manu343726 Oct 02 '13 at 14:33
  • @Manu343726: I always question the need to share ownership. Often this is a hack around a bad design, or an aversion to actually think about the problem at hand. – John Dibling Oct 02 '13 at 14:36
  • @Manu343726 : second case – Laurent Oct 02 '13 at 14:41
  • @John Dibling, maybe that is the good question, consider you have collection(s) of objects and you want also to model relationships between these object and others. You want to keep storage of the collections inside vector because you have to do some operations on all the collection and you also want to let the vector manage the allocation process. – Laurent Oct 02 '13 at 14:43
  • @Laurent so there is no ownership sharing, what do you need is a way to "abstract" a position of a vector. Write a proxy class that acts as an element of a vector, exactly as dasblinkenlight suggested. – Manu343726 Oct 02 '13 at 14:44
  • Well then, I think this is not possible with vector. If performance of insert / delete is not an issue, you could write a collection that contains two internal collections: The actual element vector, and a map that contains the original address (when the element was inserted first) as key and the current address as value. Then write an iterator that stores the original address and does to double indirection. Obviously, all elements of that vector must be update on relocation. And insert etc. will be O(n) then. – cdoubleplusgood Oct 02 '13 at 14:48
  • @Manu343726, The ownership is implicitly given to the vector and that is what i like, it does all for me. the given solutions make me think this is not the good approach or else such kind of solution will be well known. – Laurent Oct 02 '13 at 14:51
  • I'm still not understanding why you think you need to keep pointers to the elements int he vector, rather than simply running operations against the vector as you need to. Can you provide an example, maybe in a seperate question? – John Dibling Oct 02 '13 at 14:52
  • @John Dibling : I need vector for storage and to apply operation on the vector. In need pointer because my objects are not alone, they share relationship with other objects. I dont think it is a rare case, No? – Laurent Oct 02 '13 at 14:57
  • I'm just not getting it. I've had coffee. Maybe I just need to see code. – John Dibling Oct 02 '13 at 15:07
  • ok, ill try to write an example – Laurent Oct 02 '13 at 15:08

2 Answers2

2

Although std::vector does not give you such pointer, there is no reason why you cannot make one yourself. All it takes is a class that keeps a reference to the std::vector object and the index, and overloads the prefix operator * and the infix operator -> (you need four overloads - const and non-const for each operator).

You would use this pointer like this:

std::vector<int> vect = {2, 4, 6, 8, 10, 12, 14, 16};
vect_ptr<int> ptr(vect, 5); // <<== You need to implement this
*ptr = 123;
cout << *ptr << endl;

The implementation of these overloads would grab the std::vector's begin() iterator, and return the result of calling vect.at(index). This would look like a pointer from the outside, but the object to which it points would change as the content of the std::vector gets resized.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I know that is roughly what I need to do to solve my problem but I think that the good solution must be to use some already existing idiom, If not, it must seem I'm wanting something useless. – Laurent Oct 02 '13 at 14:30
  • 1
    @Laurent: I suspect you're wanting the Wrong Thing. Perhaps if you told us more about why you think you need this... – John Dibling Oct 02 '13 at 14:30
  • Its is a recurrent problem that I encounter : I have collection of objects and I like the way vector can manage the allocation process. I'm also happy with the operations that can be performed on stl containers. – Laurent Oct 02 '13 at 14:47
0

As far as I know, there is nothing in the standard library nor in Boost to address your problem. A solution would be to implement your own kind of element pointer:

template<typename T>
class vector_element
{
public:
    vector_element( std::vector<T>& v, std::size_t i )
      : m_container( v ), m_element_index(i)
    { }

    T& operator*() { return m_container[m_element_index]; }
    T* operator->() { return &m_container[m_element_index]; }
private:
    std::vector<T>& m_container;

    std::size_t m_element_index;
};
Julien
  • 2,139
  • 1
  • 19
  • 32
  • I'm sorry Julien, but I did not mention that element index do not varies. In fact insertions can invalidate your index value so your solution is not suitable – Laurent Oct 02 '13 at 14:16
  • ok, I realized that you all suggest to use index and to avoid doing insertions (except with push_back), I will think more to this kind of solution. – Laurent Oct 02 '13 at 14:24