简体   繁体   中英

Move semantics and overload

I think my understanding of rvalue references and move semantics has some holes in it.

As far as I've rvalue references understood now, I could implement a function f in two ways such that it profits from move semantics.

The first version : implement both

void f(const T& t);
void f(T&& t);

This would result in quite some redundancy, as both versions are likely to have (almost) identical implementation.

second version : implement only

void f(T t);

Calling f would result in calling either the copy or the move constructor of T .

Question. How do the two versions compare to each other? My suspicion: In the second version, (ownership of) dynamically allocated data may be moved by the move constructor, while non-dynamically allocated data in t and its members needs to be copied. In the first version, neither version allocates any additional memory (except the pointer behind the reference).

If this is correct, can I avoid writing the implementation of f basically twice without the drawback of the second version?

If you need to take a T&& parameter, it usually means you want to move the object somewhere and keep it. This kind of function is typically paired up with a const T& overload so it can accept both rvalues and lvalues.

In this situation, the second version (only one overload with T as a parameter) is always less efficient, but most likely not by much.

With the first version, if you pass an lvalue, the function takes a reference and then makes a copy to store it somewhere. That's one copy construction or assignment. If you pass an rvalue, the function again takes a reference and then moves the object to store it. That's one move construction or assignment.

With the second version, if you pass an lvalue, it gets copied into the parameter, and then the function can move that. If you pass an rvalue, if gets moved (assuming the type has a move constructor) into the parameter, and then the function can also move that. In both cases, that's one more move construction or assignment than with the first version.

Also note that copy elision can happen in some cases.

The benefit of the second version is that you don't need multiple overloads. With the first version, you need 2^n overloads for n parameters that you need copied or moved.

In the simple case of just one parameter, I sometimes do something like this to avoid repeating code:

void f(const T& t) {
    f_impl(t);
}
void f(T&& t) {
    f_impl(std::move(t));
}

// this function is private or just inaccessible to the user
template<typename U>
void f_impl(U&& t) {
    // use std::forward<U>(t)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM