Move semantics of C ++ 11

It can be copied and movable concepts

In object-oriented, some classes can be copied, such as car, house and other properties that they can be replicated, you can call the copy constructor, the object class is a little unique, class or resource is unique, such as IO, std :: unique_ptr, etc., they can not reproduce, but can put the resources to hand over ownership to the new object, called movable.
C ++ 11 one of the most important improvement is the introduction of a semantic move, so that when the construction of some objects can get to existing resources (such as memory) without the need to copy, apply for a new memory, so instead of moving copy will greatly enhance performance. For example, some rvalue imminent demise destruction, this time we move constructor can take over their resources.

And moving the mobile constructor function assignment

Consider a class A, having i member inside a stack array 500

#include <iostream>
#include <cstring>

using namespace  std;

class A{
public:
   A():i(new int[500]){
      cout<<"class A construct!"<<endl;
   }
   A(const A &a):i(new int[500]){
      memcpy(a.i,i,500*sizeof(int));
      cout<<"class A copy!"<<endl;
   }
   ~A(){
      delete []i;
      cout<<"class A destruct!"<<endl;
   }

private:
   int *i;
};

A get_A_value(){
    return A();
}
void pass_A_by_value(A a){

}
int main(){
    A a = get_A_value();
    return 0;
}

To see compile-time temporary copy of the object we closed the compiler optimization omitted CopyConstructible

g++ main.cpp -o main.exe -fno-elide-constructors -std=c++11

It can be seen running

class A construct!
class A copy!
class A destruct!
class A copy!
class A destruct!
class A destruct!

There was a structure and two copies! In each copy of the array have to reapply the memory, and the object is copied soon after the destruction, this is a waste.
We move together in the class constructor:

...
#include <iostream>
   A(A &&a)noexcept
     :i(a.i)
   {
      a.i = nullptr;
      cout<< "class A move"<<endl;
   }
...

Then compile, execute; you can see output

class A construct!
class A move
class A destruct!
class A move
class A destruct!
class A destruct!

The original structure twice to move into a twice! ! In the mobile constructor, we did it, we just acquired the resources moving objects (here the memory) of ownership, and to be a member pointer set a moving object is empty (in order to avoid moving over the memory are destructed ), did not apply this process and allocate new memory, the large number of objects in the system, configured to move relative to the copy configuration may significantly improve performance! Here noexcepttells the compiler that this does not throw an exception, so that some operations compiler province (this is to ensure that the STL container in time to re-allocate memory (know noexpect) while using a mobile structure instead of copy constructor), usually moving structure will not throw an exception.

@note: here only to demonstrate, with -fno-elide-constructions closed g ++ compiler optimizations temporary copies of objects when the function returns the value thereof is omitted. Although the compiler can optimize a lot of time for us, there are times when the compiler can not optimize the use of mobile and still need to understand semantics.

In addition to mobile constructor, assignment operator should move together to write.

   A &operator =(A &&rhs) noexcept{
      // check self assignment
      if(this != &rhs){
         delete []i;
         i = rhs.i;
         rhs.i = nullptr;
      }
      cout<< "class A move and assignment"<<std::endl;
      return *this;
   }

Summary mobile and mobile construction assignment

Summary of what writing tips move constructor and move assignment functions:

  1. Direct substitution "shallow copy" rvalue member reference object;
  2. Pointer members need to previously set reference value of the right nullptr, when the value of the right to avoid the destruction of our shallow copy resources to release;
  3. Mobile constructor need to check whether it is self-assignment before the first members of their memory delet member shallow copy and then the right values, always keep in mind Article 2.

About constructor this section there are a lot of best practice: search for "three five law", "copy and swap", "move and swap" for more information

std::move()

the role of std :: move (lvalue) is to convert a value for the left and right values. About meaning about the value of a blog on our C ++ rvalue 11 references been elaborated.

int lv = 4;
int &lr = lv;// 正确,lr是l的左值引用
int &&rr = lv; // 错误,不可以把右值引用绑定到一个左值

If you are using std :: move function

   int &&rr = std::move(lv);  // 正确,把左值转换为右值 

We can see the role of std :: move is to convert the value to the left and right values.

Let's take a look at std :: move the source code to achieve:

// FUNCTION TEMPLATE move
template <class _Ty>
_NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable
    return static_cast<remove_reference_t<_Ty>&&>(_Arg);
}

We can see std :: move is a template function, obtained by remove_ original type reference_t template parameters \, then the value of the conversion value for the right type. In the words of C ++ guru Scott Meyers in "Effective Modern C ++" in, std :: move is cast, not a move.

== It is worth noting: == Use the move means that the value is converted into a left and right value, the original value should not continue to re-use (commitment soon abandoned)

Using std :: move to achieve an efficient swap function

We can implement a semantic move switching operation, the swap ;
without using semantics Move

swap(A &a1, A &a2){
    A tmp(a1); // 拷贝构造函数一次,涉及大量数据的拷贝
    a1 = a2;   // 拷贝赋值函数调用,涉及大量数据的拷贝
    a2 = tmp;  // 拷贝赋值函数调用,涉及大量数据的拷贝
}

If Move semantics, i.e. moving together with the mobile constructor and assignment functions:

void swap_A(A &a1, A &a2){
    A tmp(std::move(a1)); // a1 转为右值,移动构造函数调用,低成本
    a1 = std::move(a2);   // a2 转为右值,移动赋值函数调用,低成本
    a2 = std::move(tmp);  // tmp 转为右值移动给a2
}

We can see the move semantics can indeed improve performance, in fact, move semantics widely used for container standard library. C ++ 11 standard library In the std :: swap also move semantics-based implementation.

Speaking of the swap, it would have to say about ah move-and-swap technology the

Move and swap tips

Look at the following piece of code to achieve a unique_ptr, and standard std :: consistent meaning unqiue_ptr of a smart pointer.

template<typename T>
class unique_ptr
{
    T* ptr;

public:

    
    explicit unique_ptr(T* p = nullptr)
    {
        ptr = p;
    }

    ~unique_ptr()
    {
        delete ptr;
    }
    
    // move constructor
    unique_ptr(unique_ptr&& source)   // note the rvalue reference
    {
        ptr = source.ptr;
        source.ptr = nullptr;
    }
    
 /*    unique_ptr& operator=(unique_ptr&& source)   // 这里使用右值引用
    {
        if (this != &source)    // beware of self-assignment
        {
            delete ptr;         // release the old resource

            ptr = source.ptr;   // acquire the new resource
            source.ptr = nullptr;
        }
        return *this;
    } */
    
    // move and swap  idiom replace the move assignment operator
    unique_ptr& operator=(unique_ptr rhs)   // 这里不用引用,会调用移动构造函数
    {
        std::swap(ptr, rhs.ptr);
        // std::swap(*this,rhs)  // is also ok
        return *this;
    }
    
    
    
    T* operator->() const
    {
        return ptr;
    }

    T& operator*() const
    {
        return *ptr;
    }
};

Here if you want to write mobile valued function in a conventional way, check the function of the body you need to write a bunch of code from a lengthy assignment and so on. Using the move-and-swap semantics, with only a brief two lines can be written. Assignment function in a mobile source is a local object, so that when the passed parameter copy constructor must call (if not realized there is no call) or a mobile constructor
, (in fact only the right can be passed in the value). Then std :: swap responsible for the original source of resources and exchange, completed the move assignment. This saves a lot of code to write, very elegant.

move-and-swap and copy-and-swap see my other blog post.

reference

The following are two data access when I found on stackoverflow thought that it was very much in place:

  • https://stackoverflow.com/questions/3106110/what-are-move-semantics/3109981#3109981

  • Text unique_ptr implementation reference https://stackoverflow.com/questions/3106110/what-are-move-semantics/11540204#11540204

Guess you like

Origin www.cnblogs.com/sunchaothu/p/11392116.html