By Colen


2009-05-28 18:04:09 8 Comments

When I do this:

std::vector<int> hello;

Everything works great. However, when I make it a vector of references instead:

std::vector<int &> hello;

I get horrible errors like

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

I want to put a bunch of references to structs into a vector, so that I don't have to meddle with pointers. Why is vector throwing a tantrum about this? Is my only option to use a vector of pointers instead?

9 comments

@ivaigult 2019-03-22 13:58:09

TL; DR

Use std::reference_wrapper like this:

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

int main()
{
    std::string hello = "Hello, ";
    std::string world = "everyone!";
    typedef std::vector<std::reference_wrapper<std::string>> vec_t;
    vec_t vec = {hello, world};
    vec[1].get() = "world!";
    std::cout << hello << world << std::endl;
    return 0;
}

Demo

Long answer

As standard suggests, for a standard container X containing objects of type T, T must be Erasable from X.

Erasable means that the following expression is well formed:

allocator_traits<A>::destroy(m, p)

A is container's allocator type, m is allocator instance and p is a pointer of type *T. See here for Erasable definition.

By default, std::allocator<T> is used as vector's allocator. With the default allocator, the requirement is equivalent to the validity of p->~T() (Note the T is a reference type and p is pointer to a reference). However, pointer to a reference is illegal, hence the expression is not well formed.

@newacct 2009-05-28 18:25:59

The component type of containers like vectors must be assignable. References are not assignable (you can only initialize them once when they are declared, and you cannot make them reference something else later). Other non-assignable types are also not allowed as components of containers, e.g. vector<const int> is not allowed.

@James Curran 2009-05-28 18:29:47

Are you saying I can't have a vector of vectors? (I'm sure I've done that...)

@Martin Cote 2009-05-28 18:31:04

Yes, a std::vector< std::vector<int> > is correct, std::vector is assignable.

@Johannes Schaub - litb 2009-05-28 18:47:33

Indeed, this is the "actual" reason. The error about T* being impossible of T is U& is just a side-effect of the violated requirement that T must be assignable. If vector was able to precisely check the type parameter, then it would probably say "violated requirement: T& not assignable"

@amit 2009-08-18 16:01:52

Checking the assignable concept at boost.org/doc/libs/1_39_0/doc/html/Assignable.html all operations except the swap are valid on references.

@cdhowie 2013-05-01 21:24:36

I think the component type must also be default-constructible, no? And references are not that either.

@Don Hatch 2014-07-02 07:06:11

@cdhowie, no, the component type need not be default-constructible, as long as you don't call resize() or the vector constructor that takes a size. (I conclude this from trying it using g++, not from reading any spec)

@Gubatron 2016-09-12 19:02:53

I had this issue trying to do: vector<vector <int>&> The solution was to work with: vector<vector<int>*>

@Post Self 2017-09-10 19:57:16

@JohannesSchaub-litb I guess it could do like static_assert<std::is_same_v<T, std::remove_reference<T>>> or something along those lines

@laike9m 2018-07-14 07:02:38

This is no longer true. Since C++11, the only operation-independent requirement for element is to be "Erasable", and reference is not. See stackoverflow.com/questions/33144419/….

@johnbakers 2019-12-08 19:51:10

References are not assignable (you can only initialize them once when they are declared, and you cannot make them reference something else later). Then why can I for (item& i: myVector) i = foo; ? I am assigning the reference to something else.

@newacct 2019-12-09 00:31:53

@johnbakers: You are modifying the thing the reference points to, not the reference itself. Modifying the reference itself would allow you to have the reference to point to something else, which is impossible with C++ references.

@Omid 2017-05-24 10:20:56

As the other comments suggest, you are confined to using pointers. But if it helps, here is one technique to avoid facing directly with pointers.

You can do something like the following:

vector<int*> iarray;
int default_item = 0; // for handling out-of-range exception

int& get_item_as_ref(unsigned int idx) {
   // handling out-of-range exception
   if(idx >= iarray.size()) 
      return default_item;
   return reinterpret_cast<int&>(*iarray[idx]);
}

@Xeverous 2018-01-19 20:11:25

reinterpret_cast is not needed

@underscore_d 2018-09-30 12:52:31

As the other answers show, we are not confined to using pointers at all.

@Steephen 2015-05-29 03:35:30

Ion Todirel already mentioned an answer YES using std::reference_wrapper. Since C++11 we have a mechanism to retrieve object from std::vector and remove the reference by using std::remove_reference. Below is given an example compiled using g++ and clang with option
-std=c++11 and executed successfully.

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

class MyClass {
public:
    void func() {
        std::cout << "I am func \n";
    }

    MyClass(int y) : x(y) {}

    int getval()
    {
        return x;
    }

private: 
        int x;
};

int main() {
    std::vector<std::reference_wrapper<MyClass>> vec;

    MyClass obj1(2);
    MyClass obj2(3);

    MyClass& obj_ref1 = std::ref(obj1);
    MyClass& obj_ref2 = obj2;

    vec.push_back(obj_ref1);
    vec.push_back(obj_ref2);

    for (auto obj3 : vec)
    {
        std::remove_reference<MyClass&>::type(obj3).func();      
        std::cout << std::remove_reference<MyClass&>::type(obj3).getval() << "\n";
    }             
}

@alastair 2016-02-18 17:36:35

I don’t see the value in std::remove_reference<> here. The point of std::remove_reference<> is to allow you to write "the type T, but without being a reference if it is one". So std::remove_reference<MyClass&>::type is just the same as writing MyClass.

@Toby Speight 2017-05-24 09:32:09

No value at all in that - you can just write for (MyClass obj3 : vec) std::cout << obj3.getval() << "\n"; (or for (const MyClass& obj3: vec) if you declare getval() const, as you should).

@Ion Todirel 2012-11-20 05:08:00

yes you can, look for std::reference_wrapper, that mimics a reference but is assignable and also can be "reseated"

@timdiels 2014-10-17 15:40:07

Is there a way of getting around calling get() first when trying to access a method of an instance of a class in this wrapper? E.g. reference_wrapper<MyClass> my_ref(...); my_ref.get().doStuff(); is not very reference like.

@WorldSEnder 2014-11-13 12:52:53

Isn't it implcitly castable to the Type itself by returning the reference?

@underscore_d 2018-09-30 12:50:16

Yes, but that requires a context that implies which conversion is required. Member access does not do that, hence the need for .get(). What timdiels wants is operator.; have a look at the latest proposals/discussions about that.

@James Curran 2009-05-28 18:21:58

By their very nature, references can only be set at the time they are created; i.e., the following two lines have very different effects:

int & A = B;   // makes A an alias for B
A = C;         // assigns value of C to B.

Futher, this is illegal:

int & D;       // must be set to a int variable.

However, when you create a vector, there is no way to assign values to it's items at creation. You are essentially just making a whole bunch of the last example.

@newacct 2009-05-28 18:35:14

"when you create a vector, there is no way to assign values to it's items at creation" I don't understand what you mean by this statement. What are "its items at creation"? I can create an empty vector. And I can add items with .push_back(). You are just pointing out that references are not default-constructible. But I can definitely have vectors of classes that are not default-constructible.

@Johannes Schaub - litb 2009-05-28 18:53:05

The element ype of std::vector<T> is not required to be default constructible. You can write struct A { A(int); private: A(); }; vector<A> a; just fine - as long as you don't use such methods that require it to be default constructible (like v.resize(100); - but instead you will need to do v.resize(100, A(1)); )

@James Curran 2009-05-28 18:53:37

And how would you write such a push_back() in this case? It will still use assignment, not construction.

@Johannes Schaub - litb 2009-05-28 19:02:39

James Curran, No default construction takes place there. push_back just placement-news A into the preallocated buffer. See here: stackoverflow.com/questions/672352/… . Note that my claim is only that vector can handle non-default-constructible types. I don't claim, of course, that it could handle T& (it can't, of course).

@Drew Dormann 2009-05-28 18:27:16

boost::ptr_vector<int> will work.

Edit: was a suggestion to use std::vector< boost::ref<int> >, which will not work because you can't default-construct a boost::ref.

@Manuel 2010-02-04 12:05:58

But you can have a vector or non default-constructible types, right? You only have to be careful not to use the default ctor. of the vector

@Lightness Races with Monica 2014-07-31 11:00:57

@Manuel: Or resize.

@Matthäus Brandl 2015-03-06 14:03:18

Be careful, Boost's pointer containers take exclusive ownership of the pointees. Quote: "When you do need shared semantics, this library is not what you need."

@Martin Cote 2009-05-28 18:30:07

As other have mentioned, you will probably end up using a vector of pointers instead.

However, you may want to consider using a ptr_vector instead!

@Klemens Morgenstern 2014-10-03 12:12:31

This answer is not workable, since a ptr_vector is supposed to be a storage. That is it will delete the pointers at removal. So it is not usable for his purpose.

@Adam Rosenfield 2009-05-28 18:07:06

It's a flaw in the C++ language. You can't take the address of a reference, since attempting to do so would result in the address of the object being referred to, and thus you can never get a pointer to a reference. std::vector works with pointers to its elements, so the values being stored need to be able to be pointed to. You'll have to use pointers instead.

@peterchen 2009-05-28 18:19:10

I guess it could be implemented using a void * buffer and placement new. Not that this would make much sense.

@Brian Neal 2009-05-28 19:28:03

"Flaw in the language" is too strong. It is by design. I don't think it is required that vector works with pointers to elements. However it is required that the element be assignable. References are not.

@David Schwartz 2016-05-17 00:11:02

You can't take the sizeof a reference either.

@Ion Todirel 2017-12-03 01:53:40

you don't need a pointer to a reference, you have the reference, if you do need the pointer, just keep the pointer itself; there is no problem to be solved here

Related Questions

Sponsored Content

22 Answered Questions

[SOLVED] Concatenating two std::vectors

26 Answered Questions

[SOLVED] What is the easiest way to initialize a std::vector with hardcoded elements?

26 Answered Questions

[SOLVED] How do I pass a variable by reference?

26 Answered Questions

37 Answered Questions

16 Answered Questions

[SOLVED] Why can templates only be implemented in the header file?

36 Answered Questions

[SOLVED] Why is "using namespace std;" considered bad practice?

3 Answered Questions

[SOLVED] Why is 'this' a pointer and not a reference?

10 Answered Questions

Sponsored Content