Vishnu TP
Vishnu TP

Reputation: 3

Why is the memory location of a variable passed to a function (moved) different from the original memory address?

Below is my code and the output for the same

fn main() {
    let a : String = String::from("variable a");
    println!("variable from main fun : {}", a);
    println!("variable mem location {:p} ", &a);
    move_function(a);
}

fn move_function(a: String) {
    println!("variable from move_function fun : {}", a);
    println!("variable mem location from move_function {:p} ", &a);
}

Output

The output for the above code is 
variable from main fun : variable a
variable mem location 0x7fff11676c70 
variable from move_function fun : variable a
variable mem location from move_function 0x7fff11676d10 

I was expecting the memory address to be the same when printed from the main() function as well as the move_function(). Could someone help me understand why they're different?

Upvotes: 0

Views: 94

Answers (2)

Finomnis
Finomnis

Reputation: 22591

Moving a variable does exactly what it says: it moves it to a different location, so it has a different address.

That said, the actual content of the string is not moved, because for a String type, only the stack part is moved. That is 24 bytes (on a 64 bit system):

  • 8 bytes: a pointer to the actual string content on the heap
  • 8 bytes: the size of the string
  • 8 bytes: the size of the allocated memory. If the string grows further than that, a reallocation happens.

If you move the string, those 24 bytes get moved. The content of the string, however, stays where it is:

fn main() {
    let a: String = String::from("variable a");
    println!("main: variable: {}", a);
    println!("main: variable mem location: {:p}", &a);
    println!("main: content mem location: {:p}", a.as_ptr());
    println!("main: size: {} bytes", std::mem::size_of_val(&a));
    move_function(a);
}

fn move_function(a: String) {
    println!("move_function: variable: {}", a);
    println!("move_function: variable mem location: {:p}", &a);
    println!("move_function: content mem location: {:p}", a.as_ptr());
    println!("move_function: size: {} bytes", std::mem::size_of_val(&a));
}
main: variable: variable a
main: variable mem location: 0x7ffc8e535ca8
main: content mem location: 0x55d52597dad0
main: size: 24 bytes
move_function: variable: variable a
move_function: variable mem location: 0x7ffc8e535de0
move_function: content mem location: 0x55d52597dad0
move_function: size: 24 bytes

Upvotes: 2

Babur Makhmudov
Babur Makhmudov

Reputation: 532

Moves are essentially a bit for bit copy (memcpy) under the hood, the only difference being that compiler also tracks ownership of the resource being moved, and doesn't allow access through the old owner after the move. So answering the question, move semantics just copies bits from source (old owner) to destination (new owner), thus changing the memory address.

Also in some cases, as far as I know, compiler might optimize away memcpy altogether, reusing the old address, but that is totally different topic.

Upvotes: 1

Related Questions