1

I have been learning about references in Rust and finding it hard to understand as on how exactly are references been stored in stack.

Consider the below program:

fn main() {
    let name = String::from("Somu");
    let name_ref = &name;
}

Now, How does memory is allocated in the stack frame for these 2 variables?

|--------------------|
| name     | 0x1fcd  |
|--------------------|
| name_ref | ?       |
|--------------------|

So, since String are stored in heap, we have the address of heap where the string "Somu" is present as the value for the variable name.

Now, name_ref is a reference to name. In Rust terms, name_ref borrows the value pointed by name.

So what get's stored in the stack frame as the value for name_ref?

  • Address to the heap memory containing the string?
  • Address of name in stack?

Or something else?

Can someone please enrich me with the concept?

Thanks in advance

Panther Coder
  • 1,058
  • 1
  • 16
  • 43
  • Some diagrams here (start reading at "Because you seem to know C++"): https://stackoverflow.com/questions/76325831/creating-an-alias-for-a-variable/76326693#76326693 – 7stud Jun 06 '23 at 01:52

3 Answers3

5

So what get's stored in the stack frame as the value for name_ref?

Address of name in stack.

References are pointers with some additional properties that compiler knows about during compilation (mutabiliy, aliasing, guarantee of pointing to existing object, lifetime of the borrow, etc.). But in the end they are just a plain old pointer under the hood. They have size of usize (except wide/fat pointers). And hold a memory address of the thing they point to.

You can verify that by printing address of a pointer using {:p} formatting:

fn main() {
    let name = String::from("Somu");
    let name_ref = &name;
    
    println!("{:p}", &name as *const _);
    println!("{:p}", name_ref);
    println!("{:p}", name.as_bytes() as *const _);
}

This could for example output:

0x7ffff3dd1350
0x7ffff3dd1350
0x55dfd62769d0

Where two first addresses are addresses of stack variable name and third address is an address of a heap allocation that String manages.

Aleksander Krauze
  • 3,115
  • 7
  • 18
2

A String can be seen as a struct with three data members.

  • a pointer to a heap-allocated storage for the utf-8 bytes constituting the text,
  • an integer for the capacity of this storage,
  • an integer for the amount of bytes actually used in this storage (<=capacity, for efficient resizing strategies).

When we say that a String is heap-allocated, it's simply a shortcut to emphasize the fact that the text (sequence of utf-8 bytes) is heap-allocated; the struct itself is probably stack-allocated (depending upon your code).

In your example, the name String (the struct) is stack-allocated, as any local variable, although the text it contains is probably heap allocated, and the name_ref simply contains the address of this struct on the stack (it points to a very near address on the stack then).

Note that this way of describing what the code does is a simplistic view of what could do a non-optimizing compiler (as in debug mode), where each variable is located in memory and has an address. When it comes to an optimizing compiler (as in release mode), many variables don't simply exist has is (with a dedicated storage in memory), they are refactored into a series of equivalent operations on registers and very few memory accesses.

prog-fh
  • 13,492
  • 1
  • 15
  • 30
0

It's a reference to the String value stored on the stack, which means that the reference would store a pointer to that value. The reference would not refer to the heap; that allocation is internal to the String.

However, in the presence of compiler optimizations, it's very likely that this kind of reference will be elided.

It's also worth noting that deref coercion allows creating a &str binding from a &String, and a &str in that case would point to the heap for a non-empty String.

cdhowie
  • 158,093
  • 24
  • 286
  • 300