Search code examples
c++c++11move

Spamming std::move is the way to go?


About std::move, here is what I can interpret, according to http://en.cppreference.com/w/cpp/utility/move :-

  • If I want to transfer ownership, I have to call std::move (or in rare case, std::forward).
  • Responsibility of std::move is calling operator=(A&& other).
  • The most essential step of the move operation is supposed to be implemented in operator=(A&&).
  • It is tricky to ensure that operator=(A&&) would be called. It need a special converter.
  • There are only two converters in the C++ world that can convert variables into xvalue (the &&) : std::move and std::forward.

Question

After adding many of std::move(std::unique_ptr) in my code, I start to worry that for such basic feature like transfer ownership, I have to heavily rely on the standard library (std::).

Do I really have to use std::move to transfer ownership?

Is spamming and hard-code calling std::move in many places of code-base a correct way to go for a high-standard program?

Should std::move be encapsulated?

They are actually a single question, but ask in different perspectives.

Edit

As request, here is my trial & error. It compiled ok.
I have no problem about the code, but I worry about its approach / pattern. https://ideone.com/y8Pcgf

class T{
    public: int value;
    public: T(int a=1234){
        value = a;
    }
};
int main() {
    std::unique_ptr<T> t1 = std::unique_ptr<T>(new T(1));
    void* databaseNew=operator new [](sizeof(std::unique_ptr<T>));
    std::unique_ptr<T>* t1ptr=static_cast<std::unique_ptr<T>*>(databaseNew);
    new (t1ptr) std::unique_ptr<T>(std::move(t1));
    return 0;
}

Solution

  • The need to explicitly move, of which you complain, was actually done on purpose. Before unique_ptr, STL had a horrid construct called auto_ptr. It would move ownership impllicitly, and was borderline unusable unless you really really really knew what you were doing.

    To make things more usable, in most cases C++ now requires you to explicitly state that you intend on moving ownership over a container, by using std::move.

    In fact, std::move is little more than a cast to an rvalue reference.

    There are cases where such an explicit specification is not necessary. For example, if the container from which you take ownership is already an rvalue (e.g. - a temporary object), then no case using std::move is necessary. For example, the following doesn't compile:

    std::unique_ptr<int> a;
    a = new int;
    

    But the following does, without needing a move:

    std::unique_ptr<int> a;
    a = std::unique_ptr<int>(new int);
    

    The reason this does not need a call to std::move, despite invoking the move operator, is that the object we move the ownership away from is already a temporary object (i.e. - an rvalue), so no cast is necessary.

    Another example is if you call a function that returns a unique_ptr. You might have to call std::move inside the function to get it into the return value, but you do not need to call std::move on the function's return value to get it into the outside unique_ptr. It is already an rvalue, and therefor no cast is necessary.