C++ Primer reading notes--object movement (use of rvalue references, mobile iterators and reference qualifiers)

Table of contents

1--rvalue reference

2--std::move

3--Move constructor

4--Move assignment operator

5--Move iterator

6--Reference qualifier


1--rvalue reference

        An rvalue reference must be bound to an rvalue reference, and an rvalue reference is obtained through && ;

        An rvalue reference can only be bound to a temporary object (an object that is about to be destroyed), that is, the referenced object will be destroyed, and the object has no other users;

        Functions returning non-reference types , together with arithmetic, relational, and bitwise post-increment/decrement operators, generate rvalues;

int i = 42;
int &r1 = i; // 左值引用,i是一个变量,是左值
int &&r2 = i * 42; // 右值引用,i*42是一个临时对象,是右值 

2--std::move

        std::move is used to obtain an rvalue reference bound to an lvalue , which is defined in the header file utility;

int &&r1 = 42; // 右值引用,但r1是一个左值
int &&r2 = std::move(r1); // 调用std::move,调用后只能对r1进行赋值或销毁,不能再使用

3--Move constructor

        The first parameter of the move constructor is an rvalue reference to the class type ;

        The move constructor must ensure that after the move, it is harmless to destroy the source object ;

        The move constructor does not allocate any new memory, it just takes over the given memory;

A::A(A &&s) noexcept : data1(s.data1), data2(s.data2), data3(s.data3){
    s.data1 = s.data2 = s.data3 = nullptr;
}
// 假定data1,data2 和 data3 均是指针
// noexcept 的作用是通过标准库对于上述构造函数不抛出任何异常
// 在移动构造函数的函数体中,对源对象的指针数据进行赋值,可以避免由于源对象析构导致释放刚刚移动的内存的问题

4--Move assignment operator

A &A::operator=(A &&sample) noexcept{
    if(this != &sample){
        data1 = sample.data1;
        data2 = sample.data2;
        data3 = sample.data3;
        sample.data1 = sample.data2 = sample.data3 = nullptr;
    }
    return *this;
}

5--Move iterator

        The dereference operator of the move iterator generates an rvalue reference , and a normal iterator can be converted into a move iterator by calling the make_move_iterator function of the standard library;

        Moving an object may destroy the original object. When you are sure that an algorithm will not access the original object after assigning a value to an element or passing it to a function , you can use the moving iterator to pass the object to the algorithm;

#include <iostream>     
#include <iterator>          
#include <string>       
#include <vector>

int main (int argc, char *argv[]){
   std::vector<std::string> foo (3);
   std::vector<std::string> bar {"A", "B", "C"};
   typedef std::vector<std::string>::iterator Iter;
   std::copy ( std::move_iterator<Iter>(bar.begin()), // 使用移动迭代器
               std::move_iterator<Iter>(bar.end()),
               foo.begin() );
   bar.clear(); // 移动 bar 后,清理
   std::cout << "foo:";
   for (std::string& x : foo) std::cout << ' ' << x;
   std::cout << std::endl;;
   return 0;
}

6--Reference qualifier

        An rvalue has no memory entity, and generally cannot call a member function or assign a value to it, but sometimes the following situations occur: that is, an rvalue calls a member function or assigns a value to an rvalue;

string s1 = "abc", s2 = "def";
auto n = (s1 + s2).find('a'); //(s1 + s2)是一个右值,对右值调用成员函数
s1 + s2 = "wc"; //(s1+s2)是一个右值,对右值赋值

        The above code is actually meaningless, but C++11 still retains this mechanism of rvalue assignment or calling member functions; by using reference qualifiers , functions can be explicitly prevented from being called by lvalue or rvalue:

class demo{
	 int get_num();   // 默认情况下,成员函数既可以被左值或右值对象调用
	 int get_num()& ;  // &显式限制成员函数必须被左值成员对象调用
	 int get_num()&& ;  //&&显式限制成员函数必须被右值成员对象调用
}

class A{
	   A& operator=(const A&);
	   A& operator=(const A&) &;
	   A& operator=(const A&) &&;
}

Guess you like

Origin blog.csdn.net/weixin_43863869/article/details/132586283