-3

Why does the address of the element ping-pong?

I have something like this:

std::vector<double> foo(...);

int main(){
    std::vector<double> x;
    x.assign(1,0.0);
    x = foo(...);
    print &x.at(0); // 0x607210

    x = foo(...);
    print &x.at(0); // 0x607240

    x = foo(...);
    print &x.at(0); // 0x607210
}

Why does the address of the element ping-pong? The base address of x remains the same, and the value x.at(0) is always correct. There's a subtlety here that I do not understand.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Rob
  • 335
  • 3
  • 5
  • 1
    Post real, compilable code. –  Feb 07 '18 at 20:22
  • What has the address of the vector to to with the address of the contained data? You assign a vector to a vector. What do you think happens? –  Feb 07 '18 at 20:29

2 Answers2

2

The foo function returns a new vector. Since the result is an r-value, it will be move-assigned to x. Since each new vector had their distinct buffers, so too will the buffers of x be distinct after each move assignment.

A buffer cannot share its address with another existing buffer, and both the returned r-value and x have overlapping lifetimes, so the buffer address has to change. But a distinct buffer can have an address of a previously destroyed buffer which is why the repetition that you observed is possible.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    And the reason the addresses alternate is that after the old vector is destructed, its memory becomes available, and by coincidence the next vector uses that memory. – Barmar Feb 07 '18 at 20:31
  • @Barmar good point. I've added that to the answer with my own wording. – eerorika Feb 07 '18 at 20:36
  • Would changing foo to const vectorfoo(); force a copy assignment, hence preserving the address of the elements of x? – Rob Feb 07 '18 at 21:41
  • @Rob Yes, it would force copy assignment. Whether the address of the elements of x are preserved, depends on what `foo` returns. Is the vector greater than capacity of `x`? Are the allocator instances equivalent (they are if you use the default one for both)? In those cases the addresses cannot be preserved. Otherwise, the behaviour seems to be unspecified by the standard: https://stackoverflow.com/questions/24260717/does-a-vector-assignment-invalidate-the-reserve – eerorika Feb 07 '18 at 22:36
0

x=foo() is assigning a std::vector<double> to x. According to this documentation, operator= always invalidates pointers, references and iterators to it's elements. It's expected that the address of the elements will change. That these addresses "ping-pong" is just the behavior you happened to observe. It's not something that can be relied on.

Consider what assigning to a std::vector means in this case. The move assignment operator will replace the underlying data of x with the underlying data of the std::vector being returned by foo(). The new array couldn't have had the same address as the one that it's replacing.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87