Is there 'Copy Elision' in Rust?

Hi everyone!

I've been using Rust for a little bit now, and in the process of trying to do more and more complicated things, I frequently 'battle the borrow checker'.

One question that recently crossed my mind, is if Rust also does some kind of 'Copy Elision', similar to what C++ does (it is required for C++ compilers to do this since C++17).

The idea in C++ is that if an object is returned by value from a function, that it is then not copied (or moved) when the function returns, but was created in the 'return' location of the function in the first place. (CPPreference can explain it better than I can; see here)

Is there a similar mechanism in place in Rust?

1 Like

I believe it's an ongoing effort to reduce low-level copying like this.

However, the stakes are different between C++ and Rust, because Rust has no user-visible effects of copy/move besides the raw object address changing. In C++ you have copy and move constructors as well as destructors where user code may execute for side effects. In Rust, copy and move are both always semantically just a memcpy, with no user code involved. Copy types can't implement Drop, so there's no destructor, and otherwise moves invalidate their source, so there's nothing accessible.

So in Rust this question of copy elision is purely one of performance, not language semantics.

5 Likes

Rust has no form of guaranteed RVO in any circumstances, though RVO often incidentally happens after inlining.

However, RVO is not a big deal in rust, because unlike in C++, these copies are never more than a memcpy of size_of::<T> bytes on the stack. Rust has no copy constructors; stack data is always memcpied on assignment/function return/etc., and if the data is not safe to have multiple copies of (I.e. it does not impl the Copy trait), then the old copy is statically marked as uninitialized; no destructor is called and the compiler forbids its reuse.

It only becomes a problem when you're trying to construct a large POD value on the heap like a Box<[u8; 1024*1024*1024]>, as there's no way to ensure no intermediate array is created on the stack without unsafe code.

6 Likes

Correct; various experiments have happened. One that comes to mind is

I'm not sure what the current status is, though.

3 Likes