Can this C++ code be changed or improved with move semantics?
Asked Answered
C

2

10
struct big_struct{
    vector<int> a_vector;
    map<string, int> a_map;
};

big_struct make_data(){
    big_struct return_this;
    // do stuff, build that data, etc
    return return_this;
}
int main(){

    auto data = make_data();
}

I have seen move semantics applied to constructors, but in this bit of code, I'm wondering if the big struct is copied entirely when returned or not. I'm not even sure it is related to move semantics. Does C++ always copies this kind of data, or is it optimized? Could this code be change or improved?

What about a function that returns a vector or a map? Is that map/vector copied?

Calgary answered 29/10, 2018 at 14:59 Comment(2)
You don't need to do anything, this is a typical use case for NRVOChuvash
Before pondering "improvements" and optimizations, always benchmark, measure and profile. Even such subjective testing as "is it good enough" might suffice (and "good enough" often is good enough). Optimizations should almost always be the last thing you do, and only if it's really needed. And before doing it, have plenty of unit-testing made, to make sure that any possible optimizations doesn't break anything. And don't forget to document all and any optimizations, as those tend to make code harder to read, understand and maintain. And profile/measure to find the actual bottlenecks.Lummox
S
12

You don't need to change anything. What you have right now is the rule of zero. Since both std::map and std::vector are moveable your class automatically gets move operations added to it.

Since return_this is a function local object it will be treated as an rvalue and it will either be moved for you or NRVO will kick in and no move or copy will happen.

Your code will either produce a default construction call for return_this and a move constructor call for data or you will see a single default constructor call for data (NRVO makes return_this and data the same thing).

Shyster answered 29/10, 2018 at 15:2 Comment(2)
When you write "either/or", does it means the compiler is free to decide which option to choose? Has C++17 introduced anything new in such a choice since C++11?Absa
@Absa The compiler is free to chose. C++17 introduced guaranteed RVO but that doesn't apply here since the object has a name. reutrn some_temporay{}; In C++17 is guaranteed to never call the move/copy constructor. return name_variable; does not get such a guarantee and probably wont. It is guaranteed to be treated as an rvalue though, so at least it will be a move instead of copy.Shyster
N
0

As stated here, your class actually has a move-constructor (implicitly generated one), so it shouldn't be copied in your code, at least once (in main).

One problem is, what you're relying upon is called NRVO, and compilers are not required to implement it (unlike its happier simpler brother, RVO.) So your struct has a chance, quite very small, to be copied in the return statement—but so small that return-by-move (like return std::move(return_this);) is never actually recommended. Chances are quite high the NRVO will actually be applied if you really have a single return statement in your function that returns a single named object.

Noblesse answered 29/10, 2018 at 15:7 Comment(2)
It has no chance to be copied. It's the name of a local object of the exact type that function returns. It will either be moved or constructed in-place under NRVO.Uzzi
There is no chance it will be copied. function local arguments are treated as rvalues in return statements so the move constructor is guaranteed to be called. The only way it won't be is if the type is not moveable.Shyster

© 2022 - 2024 — McMap. All rights reserved.