4

Beginner question.

In the following code, I was expecting v2[0]=1 would also change the value of v1, but it seems not.

push_back seems to receive T&& since C++11(ref), and std::move is equivalent to static_cast<T&&>(t); according to this answer. Also std::vector::operator[] returns reference(ref). So I thought v2.push_back(std::move(v1[0])); would make a reference to the same value.

What am I missing here? I thought the output would be 1 and 1.

#include <iostream>
#include <vector>

int main(){
    std::vector<int> v1{5}, v2;
    v2.push_back(std::move(v1[0])); 

    v2[0] = 1;

    std::cout << v1[0] << '\n';
    std::cout << v2[0] << '\n';

    // output:
    // 5
    // 1
}
starriet
  • 2,565
  • 22
  • 23
  • 2
    That's because `vector` stores copies, not references. – ALX23z Apr 09 '23 at 01:41
  • 1
    @273K `v1[0] has unspecified but valid state after moving.` No, int is unaffected by "moving" from it. – eerorika Apr 09 '23 at 01:48
  • 1
    @eerorika You are right for fundamental types, they don't have moving semantic, my statement was too common. – 273K Apr 09 '23 at 01:50
  • @273K Since I'm learning C++, any "general" case would also be helpful to me. So what if it's not a fundamental type...? – starriet Apr 09 '23 at 01:59
  • 1
    The related question might help https://stackoverflow.com/questions/61866784/c-move-semantic-with-integer – 273K Apr 09 '23 at 02:04
  • Of course "unspecified but valid state" includes the possibility of keeping the original value. – BoP Apr 09 '23 at 08:05

2 Answers2

4

So I thought v2.push_back(std::move(v1[0])); would make a reference to the same value.

v1[0] is an lvalue referring to the first element of the vector, and std::move(v1[0]) is an rvalue referring to that element. The move has little to do with the behaviour of the example.

But the elements of v2 aren't references. They are integers. So, you initialise the non-reference second element of the vector using the value of the first element through the reference. It's analogous to following simpler example:

int a = 5;
int& ref = a;
int b = ref;  // b is not a reference
b = 1;        // this has no effect on a,
              // because it is a separate object from b

std::cout << a << '\n';
std::cout << b << '\n';
eerorika
  • 232,697
  • 12
  • 197
  • 326
1

A vector like all containers can't store references. If you want v2 elements reference some elements of v1, you can use std::reference_wrapper<>.

#include <iostream>
#include <vector>
#include <functional>  // for std::reference_wrapper<>

int main() {
   std::vector<int>  v1{ 5 };
   std::vector<std::reference_wrapper<int>>  v2;
   v2.push_back( v1[0] );  // move has no sense, so illegal here

   // v2[0] = 1;   illegal a reference_wrapper is not exactly a reference
   // we must use : v2[0].get() = 1;
   // or            static_cast<int&>(v2[0]) = 1;
   v1[0] = 3;    // possible

   std::cout << v1[0] << ' ' << v2[0] << '\n';

   // output: 3 3
}

Note that referencing elements in vector v1 is not a good idea, because any modification in v1 will made all references invalid.

dalfaB
  • 436
  • 1
  • 7
  • Thanks. Could you elaborate on _"any modification in v1 will make all references invalid"_? – starriet Apr 09 '23 at 16:14
  • 1
    If we add or remove something in a vector, the vector may reorganize and the element addresses will change. All reference or pointer on its elements can then become dangling. Same if the vector is deleted. – dalfaB Apr 09 '23 at 16:56
  • Oh, so you mean, if we do `v1.push_back(6)` after your example code, `v2[0].get()` is not a reference of `v1[0]` anymore? – starriet Apr 10 '23 at 00:01
  • 1
    After a push, `v2[0]` is still a reference to somewhere but at referenced location may be or not `v1[0]`. Try to use 'v2[0]` after that push is an UB (undefined behavior). Not all containers have this drawback. for example `std::list<>`, see in https://en.cppreference.com/w/cpp/container/list – dalfaB Apr 10 '23 at 11:35
  • Thanks. Maybe one of the reasons is the chance of re-allocating when we `push_back`..? If no reallocation occurs, I don't know why the referenced location(address) can be changed. But yeah I guess that's up to the implementation if that's undefined behavior(or... 'unspecified' behavior?). Thanks for your feedback :) – starriet Apr 11 '23 at 13:54