std::swap and memory addresses

closed account (ywbpSL3A)
So I was reading C++ Primer (5th Edition) and came across this:
The fact that elements are not moved means that, with the exception of string, iterators, references, and pointers into the containers are not invalidated. They refer to the same elements as they did before the swap. However, after the swap, those elements are in a different container. For example, had iter denoted the string at position svec1[3] before the swap, it will denote the element at position svec2[3] after the swap.


Now, I thought I'd test it with the following code, expecting the pointed-to values to be switched (i.e. *p1 and *p2):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <vector>
#include <iostream>

int main() {
    std::vector<unsigned> vec1{ 0, 1, 2, 3, 4 };
    std::vector<unsigned> vec2{ 5, 6, 7, 8, 9 };

    unsigned *p1 = &vec1[ 2 ];
    unsigned *p2 = &vec2[ 2 ];

    std::cout << "p1 = " << p1 << std::endl;
    std::cout << "*p1 = " << *p1 << std::endl;
    std::cout << "p2 = " << p2 << std::endl;
    std::cout << "*p2 = " << *p2 << std::endl;

    std::swap( vec1, vec2 );
    std::cout << "---" << std::endl;

    std::cout << "p1 = " << p1 << std::endl;
    std::cout << "*p1 = " << *p1 << std::endl;
    std::cout << "p2 = " << p2 << std::endl;
    std::cout << "*p2 = " << *p2 << std::endl;

    return 0;
}


This outputs:

p1 = 00C40DA0
*p1 = 2
p2 = 00C41150
*p2 = 7
---
p1 = 00C40DA0
*p1 = 2
p2 = 00C41150
*p2 = 7


Shouldn't the values of *p1 and *p2 be different to those before the swap (i.e. shouldn't *p1 = 7 and *p2 = 2)?
Last edited on
For optimization reasons, when you swap two vectors, they exchange only with pointers to memory blocks (and their sizes). It is MUCH faster than swap every element in vector.
So before you swap, you have two blocks in memory
{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}
vec1 points to first block, vec2 points to second block

After you swap, blocks left in memory at their places,
{0, 1, 2, 3, 4}, {5, 6, 7, 8, 9}
but now vec1 points to second block, vec2 points to first block

So when you read for ex. from vec1, you got vec1[0] = 5.
https://en.cppreference.com/w/cpp/container/vector/swap2
https://en.cppreference.com/w/cpp/container/vector/swap
Exchanges the contents of the container with those of other. Does not invoke any move, copy, or swap operations on individual elements.

All iterators and references remain valid. The past-the-end iterator is invalidated.

When you swap a vector, the individual elements are not swapped.
So if vec1 contains an array with addresses {0x0, 0x1, 0x2, 0x3, 0x4}, and vec2 contains an array with addresses {0x5, 0x6, 0x7, 0x8, 0x9}, these two arrays pointers are now swapped, meaning vec1 now has addresses {0x5, 0x6, 0x7, 0x8. 0x9}.

But the data at address 0x2 (and the address itself, of course) has not changed. It is still whatever value you assigned it as. Does that help?

Edit: Removed inaccurate statement :)
Last edited on
closed account (ywbpSL3A)
Ah, I missed the whole concept. It did mention in the book before, that
<...> the elements themselves are not swapped; internal data structures are swapped.
I don't know why I thought that the values get swapped. Thanks.

This code seems to clarify any misconceptions I had:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <vector>
#include <iostream>

int main() {
    std::vector<unsigned> vec1{ 0, 1, 2, 3, 4 };
    std::vector<unsigned> vec2{ 5, 6, 7, 8, 9 };

    std::vector<unsigned> *p1 = &vec1;
    std::vector<unsigned> *p2 = &vec2;

    std::cout << ( *p1 )[ 2 ] << std::endl;
    std::cout << ( *p2 )[ 2 ] << std::endl;

    std::swap( vec1, vec2 );
    std::cout << "---" << std::endl;

    std::cout << ( *p1 )[ 2 ] << std::endl;
    std::cout << ( *p2 )[ 2 ] << std::endl;

    return 0;
}


2
7
---
7
2
Last edited on
Topic archived. No new replies allowed.