1

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?

5
  • Yes. Does this not imply that the memory addresses should be the same? Commented Jul 8, 2018 at 23:51
  • Addresses of those variables are not related to move, as well as static_cast is unrelated either. Looks like you have a mess in your head. Commented Jul 8, 2018 at 23:52
  • MSVC (VS 2017). And added the rest of code to compile. And that's what it was... &v[0] results in the same addresses. Obviously that makes senses and just missed that [minor] detail. Thank you! Commented Jul 8, 2018 at 23:55
  • @M.M, in Debug I get different results with &v but in Release mode I get the same. Commented Jul 9, 2018 at 0:00
  • @M.M Eh, yeah, nitpickers... and ignorant ones are really annoying. That term is translator's enemy. In a number of languages it called left-right association (because left association would either sound idiotic, confusing or related to politics) and if they want ISO term, then it is spelled with dash - "left-association" - for some reason (maybe because left association in politics is something else). shrugs Commented Jul 9, 2018 at 0:43

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

"I didn't run this " - why not? Why are people here so reluctant to compile and run code? It would take about a minute to do this. Every time I post a code answer here, I compile it first.
@NeilButterworth maybe you could do it and report your results, seeing as it would only take about a minute
Exactly what I was looking for! Thank you for taking the time out to write/explain this. For some reason, I missed taking the address after indexing into the vector (i.e. the contents are being moved).
@NeilButterworth , because many people read and answer questions on their cell phone, and I don't have a compiler on it.
4

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".

2 Comments

Since C++17 there is no temporary return value at all , the result object of the function is v in main
@M.M right. I "removed" the parts implying such (in strike-through, in case pre-C++17 users read this).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.