Move semantic notes
Tags: cpp
Published: 2017-07-30 17:45:16

---
title: Move semantic notes
published: true
description: Notes from Effective Modern C++
tags: cpp
---
From Item 23:

* `std::move` cast a value (no matter what kind of value it is) to a rvalue. An approximate implementation is:


```C++
//C++ 14
template<typename T>
decltype(auto) move(T&& param)
//C++ 11
template<typename T>
typename remove_reference<T>::type&&
{
    using ReturnType = remove_reference_t(T)&&;
    return static_cast<ReturnType>(param);
}

```

* If you want to move anything, don't declare it to be `const`. Think about how string and vector are moved.

* Fill in the gap here on how `std::forward` actually works, but conceptually it is just a cast as well, a conditional cast.

From Item 24:

* Two examples of `universal/forwarding references`:

```C++
template<typename T>
void f(T&& param); // param is universal reference

auto&& var2 = var1; // var2 is universal reference
```

Universal references come from type deduction (see examples above). 

Why do we need to know this? --> Not sure at this moment.

From Item 25:

*Use std::move on rvalue references and std::forward on universal references*

The first take away for me here, which seems a bit surprising still, is this example:

```C++
class Widget {
    public:
    Widget(Widget&& rhs)
    : name (std::move(rhs.name)),
      p(std::move(rhs.p)
    { ... }
    ...
}
```
So why do we need `std::move` for `rhs.name`? That is because `rhs` is actually a lvalue, not a rvalue. See my [SO question](https://stackoverflow.com/questions/45520884/why-do-we-need-stdmove-in-constructors-initialisation-list) here for a more detailed explanation.

This item actually explained a few rules to apply when you write your code. Let me go through them for you:

1. use `std::move` for rvalue reference and `std::forward` for universal reference respectively, if inside your function there are multiple usages of the reference, you might just want to apply `std::move` and `std::forward` for the last usage

2. If you are returning a rvalue reference passed as a function parameter, the rule above still applies, you have to use `std::move` or `std::forward` to achieve the optimal

3. But if you are returning a local object, don't use `std::move` because that will invalidate RVO (return value optimisation) for the compiler.



From Item 26 & 27
*Avoid overloading on universal references*

This is because overloading on universal references can take a very high priority when the compiler tries to resolve overloaded function and thus cause confusion. This is especially true for constructors. But sometimes we cannot avoid this, again, especially for constructors since we have to overload them. In item 27 Scott introduced us some techniques to resolve this issue. I think the most important one is using tag dispatch.

So what is tag dispatch?

<.... revisit item 26 and 27 later ... >

Item 28

This item just states two rules:

1. Although programmers cannot declare "reference to reference", the compiler is allowed to generate "reference to reference" in certain context.

2. When we have reference to reference, a rule called reference collapsing comes into play, in short, it states:

> If either reference is an lvalue reference, the result is an lvalue ref. Otherwise, it is a rvalue ref.