1

I saw several places (e.g) where 2-dim vector can be initialized like this

vector<vector<int> > vec(3, vector<int>(2, 0));

What I am thinking is that this code is evaluated to following

auto tmp = vector<int>(2, 0);
vector<vector<int> > vec(3, tmp);

If I am correct, then 3 elements of vec all refer to a same reference. Which means that modifying vec[0][1] also modifies vec[1][1].

If I am wrong, how does C++ make the initialization of each element in vec be a different reference?

Sang
  • 4,049
  • 3
  • 37
  • 47
  • 3
    Arguments get copied so they won't refer to the same object. – songyuanyao Apr 14 '20 at 02:46
  • 1
    If they all were to refer to the same object, then modifying any one of the three elements would result in the whole object being changed altogether. – Ruks Apr 14 '20 at 02:49
  • 1
    You're obviously used to another language where reference semantics is the default. In C++ value semantics is the default, so the default is that `tmp` will be copied three times (three distinct instances created, which are all a copy of `tmp`) not referred to three times. (It is possible to explicitly force reference semantics, but that isn't done with `std::vector`) – Peter Apr 14 '20 at 02:49
  • @Peter this means that even with my pseudo code (the latter code with `tmp`), all 3 elems of `vec` also refer to different vectors – Sang Apr 14 '20 at 02:51
  • @transang Yes, all three elements are different instances but having same value set of tmp. – Louis Go Apr 14 '20 at 02:53
  • Note: `vector`s of `vector`s can be surprisingly slow because the memory used could be scattered, making it harder for the CPU to take full advantage of the cache. Consider using [something like this](https://stackoverflow.com/a/2076668/4581301) instead. – user4581301 Apr 14 '20 at 03:40
  • @user4581301 do you have any example to show that memory used by vector is scattered. So far, I have been using a for loop for iterate over any vector with the assumption that their elements have consecutive memory addresses – Sang Apr 14 '20 at 06:47
  • 1
    Each `vector` contains a pointer to a dynamically allocated array, so a `vector` is contiguous. A `vector` of `vector`s requires multiple `vectors`, each with their own pointer to their own dynamically allocated array. The outer `vector` contains a pointer to an array of the inner `vector`, and each of the inner `vector`s contains a pointer do a different array containing its row or column of data. – user4581301 Apr 14 '20 at 14:40

2 Answers2

2

By default, almost all C++ containers (including std::vector) take their arguments by copy, so:

auto tmp = vector<int>(2, 0);
vector<vector<int> > vec(3, tmp);

Now, the vector creates three copies of 'tmp' completely unrelated to each other and stores it inside itself.


Note that however, what you are trying to do is possible, by using a std::reference_wrapper, like so: std::vector<std::reference_wrapper<std::vector<int>>>.

Example:

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

int main()
{
    auto tmp = std::vector<int>(2, 0);
    std::vector<std::reference_wrapper<std::vector<int>>> a(3, std::ref(tmp));
    a[0].get()[0] = 2;
    a[1].get()[1] = 10;
    a[2].get()[0] = 30;
    std::cout << "'tmp' contains: ";
    for (auto const& elem : tmp)
        std::cout << elem << " ";
}

Output:
'tmp' contains: 30 10

Ruks
  • 3,886
  • 1
  • 10
  • 22
0

From the constructor reference

3) Constructs the container with count copies of elements with value value.

There are no references to tmp, just copies. All the individual vectors are distinct, and modifying one won't modify any of the others.

cigien
  • 57,834
  • 11
  • 73
  • 112