C ++ 11 new features: Move semantics (mobile semantics)

Source: Internet
Author: User

C ++ 11 new features: Move semantics (mobile semantics)

What is the significance of passing by value?
When a function parameter is passed by value, this will be copied. Of course, the compiler knows how to copy data.
For our custom types, we may need to provide a copy constructor.

However, copying is expensive.

Therefore, we need to find a method to avoid unnecessary copying, that is, the mobile semantics provided by C ++ 11.
One sentence in the previous blog is used:

# Include
  
   
Void f (int & I) {std: cout <lvalue ref: <I <;} void f (int & I) {std :: cout <rvalue ref: <I <;}int main () {int I = 77; f (I); // lvalue ref called f (99 ); // rvalue ref called f (std: move (I); // return 0 will be introduced later ;}
  

In fact, the right value reference is used to create a mobile constructor and a mobile value assignment operation.

A mobile constructor is similar to a copy constructor. It takes the Instance Object of the class as a parameter and creates a new instance object.
However, the mobile constructor can avoidMemory reallocationBecause we know that the right value reference provides a temporary object instead of copying, we can move it.

In other words, when we design a temporary object, the right value reference and moving semantics allow us to avoid unnecessary copies. We do not want to copy the temporary object to be deleted, so the resource of this temporary object can be used as another object.

The right value is a typical temporary variable and can be modified. If we know that a function parameter is a right value, we can use it as a temporary storage. This means we need to move the content of the right value parameter instead of copying it. This will save a lot of space.

The Code is as follows:

#include 
  
   #include class A{public:    // Simple constructor that initializes the resource.    explicit A(size_t length)        : mLength(length), mData(new int[length])    {        std::cout << A(size_t). length =         << mLength << . << std::endl;    }    // Destructor.    ~A()    {    std::cout << ~A(). length =  << mLength << .;    if (mData != NULL) {            std::cout <<  Deleting resource.;        delete[] mData;  // Delete the resource.    }    std::cout << std::endl;    }    // Copy constructor.    A(const A& other)        : mLength(other.mLength), mData(new int[other.mLength])    {    std::cout << A(const A&). length =         << other.mLength << . Copying resource. << std::endl;    std::copy(other.mData, other.mData + mLength, mData);    }    // Copy assignment operator.    A& operator=(const A& other)    {    std::cout << operator=(const A&). length =              << other.mLength << . Copying resource. << std::endl;    if (this != &other) {        delete[] mData;  // Free the existing resource.        mLength = other.mLength;            mData = new int[mLength];            std::copy(other.mData, other.mData + mLength, mData);    }    return *this;    }    // Move constructor.    A(A&& other) : mData(NULL), mLength(0)    {        std::cout << A(A&&). length =               << other.mLength << . Moving resource.;        // Copy the data pointer and its length from the         // source object.        mData = other.mData;        mLength = other.mLength;        // Release the data pointer from the source object so that        // the destructor does not free the memory multiple times.        other.mData = NULL;        other.mLength = 0;    }    // Move assignment operator.    A& operator=(A&& other)    {        std::cout << operator=(A&&). length =               << other.mLength << . << std::endl;        if (this != &other) {          // Free the existing resource.          delete[] mData;          // Copy the data pointer and its length from the           // source object.          mData = other.mData;          mLength = other.mLength;          // Release the data pointer from the source object so that          // the destructor does not free the memory multiple times.          other.mData = NULL;          other.mLength = 0;       }       return *this;    }    // Retrieves the length of the data resource.    size_t Length() const    {        return mLength;    }private:    size_t mLength; // The length of the resource.    int* mData;     // The resource.};
  

Mobile Constructor
Syntax:

A(A&& other) noexcept    // C++11 - specifying non-exception throwing functions{  mData =  other.mData;  // shallow copy or referential copy  other.mData = nullptr;}

The most important thing is that new resources are not used, instead of being copied.
Suppose an address points to an array with 1 million int elements. We didn't create anything using the move constructor, so the cost is very low.

// Move constructor.A(A&& other) : mData(NULL), mLength(0){    // Copy the data pointer and its length from the     // source object.    mData = other.mData;    mLength = other.mLength;    // Release the data pointer from the source object so that    // the destructor does not free the memory multiple times.    other.mData = NULL;    other.mLength = 0;}

Moving is faster than copying !!!

Moving Value assignment operator
Syntax:

A& operator=(A&& other) noexcept{  mData =  other.mData;  other.mData = nullptr;  return *this;}

The workflow is as follows: what Google says:

Release any resources that * this currently owns.
Pilfer other's resource.
Set other to a default state.
Return * this.

// Move assignment operator.A& operator=(A&& other){    std::cout << operator=(A&&). length =               << other.mLength << . << std::endl;    if (this != &other) {      // Free the existing resource.      delete[] mData;      // Copy the data pointer and its length from the       // source object.      mData = other.mData;      mLength = other.mLength;      // Release the data pointer from the source object so that      // the destructor does not free the memory multiple times.      other.mData = NULL;      other.mLength = 0;   }   return *this;}

Let's look at the benefits of several moves!
As we all know, after C ++ 11, vector has been optimized. For example, vector: push_back () is defined as an overload of two versions. One is the cosnt & left value as the parameter, and the other is the T & right value as the parameter. For example, the following code:

std::vector v;v.push_back(A(25));v.push_back(A(75));

The above two push_back () calls push_back (T &) versions because their parameters are the right value. This improves the efficiency.

When the parameter is left, push_back (const T &) is called &).

#include 
  
   int main(){    std::vector
   v;    A aObj(25);       // lvalue    v.push_back(aObj);  // push_back(const T&)}

But in fact, we can use static_cast to force:

// calls push_back(T&&)v.push_back(static_cast(aObj));

We can use std: move to complete the preceding task:

v.push_back(std::move(aObj));  //calls push_back(T&&)

It seems that push_back (T &) is always the best choice, but remember:
Push_back (T &) makes the parameter null. If we want to retain the parameter value, we need to use the copy instead of moving.

Write an example to see how to use move to exchange two objects:

#include 
  
   using namespace std;class A{  public:    // constructor    explicit A(size_t length)        : mLength(length), mData(new int[length]) {}    // move constructor    A(A&& other)    {      mData = other.mData;      mLength = other.mLength;      other.mData = nullptr;      other.mLength = 0;    }    // move assignment    A& operator=(A&& other) noexcept    {      mData =  other.mData;      mLength = other.mLength;      other.mData = nullptr;      other.mLength = 0;      return *this;    }    size_t getLength() { return mLength; }    void swap(A& other)    {      A temp = move(other);      other = move(*this);      *this = move(temp);    }    int* get_mData() { return mData; }  private:    int *mData;    size_t mLength;};int main(){  A a(11), b(22);  cout << a.getLength() << ' ' << b.getLength() << endl;  cout << a.get_mData() << ' ' << b.get_mData() << endl;  swap(a,b);  cout << a.getLength() << ' ' << b.getLength() << endl;  cout << a.get_mData() << ' ' << b.get_mData() << endl;  return 0;}
  

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.