简体   繁体   中英

Why does function return not move vector?

I'm using C++17 after a long stint with C# and working through some Project Euler problems to get my feet well. Anyway, can anyone explain why createRandomVector(const int n) is not "moving" the vector created? I output the memory addresses and they only stay the same when passed by reference (obviously). Below is the code:

#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <random>

using namespace std;

auto createRandomVector(const int n)
{
    vector<int> v(n);

    iota(begin(v), end(v), 1);
    shuffle(begin(v), end(v), std::mt19937());

    cout << &v << endl;
    return v;
}

void printVector(const vector<int>& v, ostream& os);

int main()
{
    auto v = createRandomVector(100);
    printVector(v, cout);

    cout << endl;

    cout << &v << endl;
    return 0;
}


void printVector(const vector<int>& v, ostream& os)
{
    cout << &v << endl;
    for_each(begin(v), end(v), [&os](auto& i)
    {
        os << i << " ";
    });
}

Here is the output:

00BBFC20
00BBFD38
100 73 64 ... 85 90
00BBFD38

Why does the 1st memory address not match the 2nd? I have some understanding of how move works in modern C++ (a static_cast). But why is this not working?

There's 2 issues here: moving, and copy elision.

First of all, moving: Move means that there are two different objects and the contents of one are transferred to the other. (As opposed to the contents of one being copied to the other). In C++ an object has a fixed address for its entire lifetime.

Example snippet:

vector<int> a { 1, 2, 3, 4, 5 };
vector<int> b;
cout << &a << ", " << &a[0] << '\n';
b = std::move(a);
cout << &b << ", " << &b[0] << '\n';

I didn't run this so hopefully there are no typoes but you should see that, even though the two vectors are different, the block of int objects has been transferred from one to the other.

If you add to your program an output of &v[0] you should see this same effect.


Secondly, copy elision . The C++ Standard makes it optional, in this scenario, for the local variable v in createRandomVector to actually be created in the memory space set aside for v in main . In which case there would not even be any move or copy operation associated with the return step.

The conditions this can happen are when a function returns by value, and the return statement has the form: return X; where X is the name of a local variable with no embellishment.

If the compiler does take this option then the first two outputs of your program would be the same. Apparently, your compiler only decides to do this in Release Mode.

Why does the 1st memory address not match the 2nd?

They are different objects, so there is no requirement for them to have the same memory address.

However, second object might reuse the storage of the first. Such optimisation - that is, constructing the local automatic variable in place of the return value thereby eliding its copy-initialization (by move) from the local variable - is called named return value optimisation .

The return value itself is a temporary though, and there is another move from the temporary into the local variable in the calling scope. This move can also be elided. Edit: No longer applies since C++17.

So, another answer to your question would be: Because the compiler did not either perform named return value optimisation , or it didn't elide the move from the return value. Such optimisations are not mandatory, and are performed at the discretion of the compiler.

in Debug I get different results with &v but in Release mode I get the same.

It is quite typical for compilers to not perform certain optimisations in debug mode.

Why does function return not move vector?

The vector was moved in the sense that v was move-constructed. But it appears that you mean something else by "move".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM