0

This code below doesn't work because I push_back the vectors a and b to the vector vector and then alter the vectors a and b. I want to alter the vectors a and b so that the vector vector suffers the same modifications. How do I do this?

#include <iostream>
#include <vector>

int main()
{
std::vector<std::vector<int>>vector;
std::vector<int>a;
std::vector<int>b;
vector.push_back(a);
vector.push_back(b);
for (int i = 1; i <= 10; i++)
    a.push_back(i);
for (int i = 11; i <= 20; i++)
    b.push_back(i);
std::cout << vector[1][0];
std::cin.get();
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Work with the vector directly - e.g. `vector[0].push_back(i)` in the first loop rather than `a.push_back(i)`. – Peter May 31 '18 at 00:50

4 Answers4

11

You can use std::reference_wrapper (since 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.

e.g.

std::vector<std::reference_wrapper<std::vector<int>>> v;
std::vector<int> a;
std::vector<int> b;
v.push_back(a);
v.push_back(b);
for (int i = 1; i <= 10; i++)
    a.push_back(i);
for (int i = 11; i <= 20; i++)
    b.push_back(i);
std::cout << v[1].get()[0]; //11

LIVE

Note that if the vector has longer timelife than a and b, then when a and b get destroyed the references stored in the vector become dangled.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • 1
    One problem here is that `v` contains references to `a` and `b` after they go out of scope. – Sid S May 31 '18 at 01:38
5

Create v (vector is not a good name since it shares with the library and makes the code confusing) to be a vector of vector pointers (since a vector of references is not possible):

std::vector<std::vector<int> *> v; //declare as vec of vec pointers
...
v.push_back(&a); //push_back addresses of a and b
v.push_back(&b);
...
std::cout << v.at(1)->at(0) //dereference and call at on the inner vec

Note that this can be dangerous if a or b go out of scope before v, as that will leave you with dangling pointers, a mess of undefined behavior and a murder time-consuming bugs.

scohe001
  • 15,110
  • 2
  • 31
  • 51
  • This is dangerous if the vector (or a copy of it) outlives `a` or `b`, since it will contain dangling references. – Peter May 31 '18 at 00:51
1

The basic issue is that push_back copies its parameter to the end of the vector. To modify the object in the vector, you need to get a reference to it. One approach:

std::vector< std::vector<int> > my_vector;
my_vector.reserve(2);  // Going over the allocation invalidates references

my_vector.push_back( std::vector<int>() );
std::vector<int> & a = my_vector.back();

my_vector.push_back( std::vector<int>() );
std::vector<int> & b = my_vector.back();

(I changed the name of the variable because using "vector" as a variable name tends to lead to confusion.)

If you can use C++17, there is a way to reduce the lines of code using emplace_back.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • `emplace_back` exists in C++11 and C++14 as well. – Matt May 31 '18 at 00:29
  • @Matt true, but before C++17, its return type was `void`. – JaMiT May 31 '18 at 00:30
  • 2
    Just be careful, because if the second `push_back` grows the vector's capacity, the reference obtained from the earlier `back()` will become invalid. – Remy Lebeau May 31 '18 at 00:32
  • @JaMiT very true, I didn't see where you were going but now it's clear. – Matt May 31 '18 at 00:34
  • @RemyLebeau good point. I've added a reservation to avoid that. And I admit there are probably better ways to do things; it's just tough to pick one without seeing the larger picture. – JaMiT May 31 '18 at 00:39
0

If you know the number of vectors ahead of time you can do it like this:

std::vector<std::vector<int>> v(2);
std::vector<int> &a = v[0];
std::vector<int> &b = v[1];
...
Sid S
  • 6,037
  • 2
  • 18
  • 24