26

Is it legal to have a vector of references to objects, like the following?

vector<Agent&> seenAgents;

Which would for example be populated by some, but not all of the objects in the scene?

I have a vector of Agent objects, but the vector outlined above should hold references to only the ones each agent can currently see - meaning that the references will be being added and removed all the time.

Is this something the language will allow? And in addition, is there anything else I need to be aware of? If I remove a reference from the vector does it persist anywhere? Is it a memory leak?

I seem to be getting this error on the line declaring the vector:

error C2528: 'pointer' : pointer to reference is illegal

Is this something directly to do with the line or is it most likely occurring somewhere else? It's being initialised in the constructors initialiser list like this:

seenAgents(vector<Agents&>())
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dollarslice
  • 9,917
  • 22
  • 59
  • 87
  • Duplicate of http://stackoverflow.com/questions/922360/why-cant-i-make-a-vector-of-references –  Nov 20 '11 at 10:30

4 Answers4

26

You can't have vector of references, as a reference is not copyable assignable and all STL containers are supposed to store copyable assignable items.

But you can make the container to hold pointers. Like this:

vector< Agents* > seenAgents;

This is a little dangerous. You need to be sure that these pointers will remain valid. I mean - if someone deletes an object, pointed by a pointer in this container, the pointer becomes invalid. You need to be sure that this will not happen, because you can't check it (you can't check for NULL, because a pointer will not become NULL, if someone deletes the pointed object).

The best solution here (provided by container with pointers) would be to use some smart pointers - some with reference count, for example; they will guarantee you that the object will exist and that the pointer is valid. And in case that the object, pointed by the smart pointer, is destroyed, you can check it for NULL.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • 2
    Are you sure references are not copyable? I would have thought they are not assignable. – UncleBens Nov 20 '11 at 10:22
  • Right, thanks. But you still cannot "copy" a reference, as it's not a real type, it doesn't really exist, I mean - no momory is allocated for it (in most compiler implementations, pretty sure - all of them). But still - yep, `assignable` sounds more right and less confusing. Edited :) – Kiril Kirov Nov 20 '11 at 10:31
  • You can't default construct them either. –  Nov 20 '11 at 10:55
  • 1
    True. BTW, thanks for finding the duplicated, voted for closing. – Kiril Kirov Nov 20 '11 at 10:55
9

You can use std::reference_wrapper instead in C++11:

std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.

Example:

#include <functional>
#include <vector>
#include <iostream>

int main(int argc, char *argv[])
{

  int a = 5;
  int b = 6;
  std::vector<std::reference_wrapper<const int>> v;
  v.push_back(a);
  v.push_back(b);

  for (const auto& vi: v)
  {
    std::cout << vi << std::endl;
  }
  return 0;
}

https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

bergercookie
  • 2,542
  • 1
  • 30
  • 38
8

You can't do it. Use pointers.

The Boost library provides PTR_VECTOR which is a better solution than:

vector<T*> foo;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CyberGuy
  • 2,783
  • 1
  • 21
  • 31
  • 4
    Why is `ptr_vector` better then `vector`. When you say that something is better then something else describe your metric. – tomas789 Oct 21 '13 at 13:41
  • 1
    There are many reasons why `ptr_vector`s are better, you can [read about it here](http://www.boost.org/doc/libs/1_55_0/libs/ptr_container/doc/examples.html). But, in a nutshell, they operate more like a vector of references would and are, therefore, generally safer to use. For example, you don't dereference the pointers yourself and you can't store a `NULL` pointer in the vector. – edam Jul 15 '14 at 14:14
  • 1
    Ooops, I meant to say "you can't store a `NULL` pointer in the vector" *by default*! – edam Jul 15 '14 at 14:28
2

I wanted similar functionality. In the end, here is what I did:

template <class T> class VectorOfRefs : public std::vector<T *> {
public:
    inline T & at( const uint64_t i ) {
        T * x = std::vector<T *>::at( i );
        return *x;
    }
};

VectorOfRefs < MyType > myVector;
myVector.push_back( &myInstance0 );
myVector.push_back( &myInstance1 );

// later in the code:
myVector.at( i ).myMethod();

Obviously this is a vector of pointers underneath the covers.

Normally I would use STL and settle for myVector.at( i )->myMethod(), but I wanted to use the ++ operator, so I had the following two options:

// using STL:
(*myVector.at(i))++;

// or, using my wrapper:
myVector.at( i )++;

I find the notation with the wrapper far preferable in terms of code readability. I don't like the wrapper, per se, but it pays dividends later.

etep
  • 93
  • 5