Equivalent C++ code for variable bindings


#1

Hi, can you tell me what is the equivalent C++ code for the following rust code …

fn foo() {
    let v = vec![1, 2, 3];
}

Is this equivalent to …

void fooCpp() {
    vector<int> *v = new vector<int>();
    *v = {1, 2, 3};
    delete v;
}

Or this …

void fooCpp2() {
    vector<int> v = {1, 2, 3};
}

Or something else altogether?


#2

Second. All variables are on stack by default. Rust std contains some structs for Heap-allocated. For example Rc, Box.
http://doc.rust-lang.org/book/the-stack-and-the-heap.html


#3

This is nice, thanks!


#4

Actually it’s the first one.

By looking at this code as example

https://play.rust-lang.org/?gist=55ba0e1db0224e205715&version=stable

fn main() {
    let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    println!("{:?}", v[0]);
}

And look at the disassembly

	mov	esi, 4
	call	__rust_allocate@PLT
	mov	rbx, rax
	test	rbx, rbx
	je	.LBB0_1
	mov	rax, qword ptr [rip + const4278+32] ; moves constant data to mem
	mov	qword ptr [rbx + 32], rax
        ...
.Ltmp0:
	lea	rdi, [rsp + 24]
	call	_ZN2io5stdio6_print20hb562e3e90d717742EehE@PLT
.Ltmp1:
	mov	esi, 40
	mov	edx, 4
	mov	rdi, rbx
	call	__rust_deallocate@PLT

I have slightly made the disassembly code smaller but that’s the important parts of it.


#5

I think the point is that automatic variables are stored on the stack in C++ and Rust alike and

new vector<int>()

corresponds to

Box::new(Vec::<i32>::new())

Internally both vectors allocate their storage on the heap but that is a different story.


#6

As from the documentation:

Most fundamentally, Vec is and always will be a (pointer, capacity, length) triplet. No more, no less.

and

If a Vec has allocated memory, then the memory it points to is on the heap (as defined by the allocator Rust is configured to use by default), and its pointer points to len() initialized elements in order (what you would see if you coerced it to a slice), followed by capacity() - len() logically uninitialized elements.

I hope this answers the question.

Although you should really read the docs linked above as there is a lot of different behaviour when e.g. using ZSTs.


#7

I hope a future escape analysis pass of Rustc will stack-allocate small Vecs that don’t escape. Nailing down a semantics that is sub-optimal is… suboptimal.


#8

In C++, std::vec<int> v { 1, 2, 3 }; still allocates its storage on the heap because the std::vec constructor runs in its own stack frame — and because of the way stack frames (typically) work, function-call semantics usually deny the possibility of use a helper function for stack allocation.


#9

Until then, there’s https://crates.io/crates/smallvec .


#10

But if have allocated a struct on the heap (with box or something) smallvec doesn’t help you… So, can Clippy perform escape analysis on a whole Crate and warn me where I can avoid a Box/Vec? It’s worse than having this pass in Rustc, but better than having nothing.


#11

The latter would be more like unique_ptr<vector<int>>(new vector<int>()), actually.


#12

So I suppose a pedantic translation of

new vector<int>()

would then be this?

Box::into_raw(box Vec::<i32>::new())

#13

No, that’s unique_ptr<vector<int>>(new vector<int>()).release() :slight_smile:
But probably as close as you can get to new vector<int>() in Rust.