I'd push back slightly on move — at small scale the opposite has been true for me.
Not sure what you mean, but std::move is one of the greatest tools in C++
Move in C++ without a std:move
11–20 of 75 posts
Re: Move in C++ without a std:move
#12What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
I'm not too confident on that last part, because such an implementation would mess with semantics in case of an exception, so anyone feel free to correct me on that.
Re: Move in C++ without a std:move
#13What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter, which is written to before returning. If you're returning a newly-constructed object, the compiler can rewrite that into calling the constructor on the pointer, but if you're returning a named object, the class may have a non-trivial destructor that needs to run after the move…
This sounds wrong, are you sure? Would you mind demonstrating with an example on godbolt? Whether NRVO applies or not, the ABI should be the same, AFAIK.
Re: Move in C++ without a std:move
#14What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
In RVO there is no problem because you know what object is the one you need to put there.
In NRVO there is a problem because you might have one of multiple objects being returned and you need to know which one to construct at the call site; it can't be all of them on top of each other. But you don't necessarily know at the time of construction whether that object will be the one that is actually returned. Doing so requires imperfect code analysis so the standard would need to define the complicated analyses to perform.
Re: Move in C++ without a std:move
#15What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
NRVO requires the compiler to analyze the flow, like if 2 different variables/constructions can lead to the return (what one do we take, or can we do either later?).
Also, with RVO it's easy to detect and elide destruction calling for things going out of scope whilst NRVO would require more careful management of destruction order,etc.
Basically, NRVO touches a lot of things in "inconventient" places that can easily require reworking internal compiler structures to track destinations whilst RVO was probably far easier to just "hack in".
Re: Move in C++ without a std:move
#16Earlier quoted context omitted.
N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter, which is written to before returning. If you're returning a newly-constructed object, the compiler can rewrite that into calling the constructor on the pointer, but if you're returning a named object, the class may have a non-trivial destructor that needs to run after the move…
> N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter This sounds wrong, are you sure? Would you mind demonstrating with an example on godbolt? Whether NRVO applies or not, the ABI should be the same, AFAIK.
Re: Move in C++ without a std:move
#17What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
I recall reading that at a high level RVO is implemented by treating the return value as an external object. In simple terms (simplistic terms) RVO then works by
- first instantiating the return variable,
- passing the var by reference to the function,
- and then use return value to actually initialize the variable passed by reference.
The moment there's some funny logic on what to write to that output value, the problem gets far more complex.
Re: Move in C++ without a std:move
#18What is that makes NVRO so much more difficult to implement? Why couldn't they mandate that just like RVO? Do compilers literally just special case a simple return statement of a direct construction or something?
RVO is easy to detect since it happens only in expressions in return-statements. NRVO requires the compiler to analyze the flow, like if 2 different variables/constructions can lead to the return (what one do we take, or can we do either later?). Also, with RVO it's easy to detect and elide destruction calling for things going out of scope whilst NRVO would require more careful management of destruction order,etc. Ba…
Maybe it's the guaranteed elision that makes it a problem, like you can't fail the analysis, but then maybe you go the rust route - fail to compile and urge the programmer to rewrite their code so it accepts it.
Make it opt in with [[must_elide]] so old code still works I guess.
Re: Move in C++ without a std:move
#19Earlier quoted context omitted.
N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter, which is written to before returning. If you're returning a newly-constructed object, the compiler can rewrite that into calling the constructor on the pointer, but if you're returning a named object, the class may have a non-trivial destructor that needs to run after the move…
> N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter This sounds wrong, are you sure? Would you mind demonstrating with an example on godbolt? Whether NRVO applies or not, the ABI should be the same, AFAIK.
I will say before testing this i didn't realize the RVO calling convention was to return the pointer you pass in, but apparently so. If makeS2() returned void, it's just a tail call to the constructor, but makeS1() has to spill rbx and use it to save the pointer.
Re: Move in C++ without a std:move
#20Earlier quoted context omitted.
Not sure what you mean, but std::move is one of the greatest tools in C++
This is one case where Rust benefited from C++’s experience — move by default with opt-in clone/copy is IMO the better setup.