0


15、lambda表达式、右值引用、移动语义

前言

返回值后置

auto 函数名 (形参表) ->decltype(表达式)

lambda表达式

lambda表达式的名称是一个表达式 (外观类似函数),但本质绝非如此

语法规则

[捕获表] (参数表) 选项 -> 返回类型
{
函数体;
}

lambda表达式的本质

  • lambda表达式本质其实是一个类
  • 并且最终返回值为这个类的对象
  • 因此对lambda表达式的调用就是该对象的函数操作符的调用

简写

  • 可以没有返回值类型,将根据return推断
  • 如果连return也没有,则返回值为void
  • 参数为void可以省略不写

捕获表

  • []:不捕获任何外部变量
  • [variable] : 捕获外部变量的值(具备只读属性)
  • [&variable]: 按引用捕获,指定的外部变量
  • [this]: 捕获this指针,访问外部对象的成员
  • [=]: 按值捕获所有的外部变量,也包括this
  • [&]: 按引用捕获所有的外部变量,也包括this
  • [=,&variable]: 按值捕获所有的外部变量包括this,但是指定的外部变量按引用捕获
  • [&,=variable]: 按引用捕获所有的外部变量,也包括 this,但是指定的外部变量按值捕获
// lambda表达式
#include <iostream>
#include <typeinfo>
using namespace std;

int Max(int x, int y){
    return x > y ? x : y;
}

int main( void ){
    int a = 10, b = 20;

    cout << Max(a,b) << endl;;
    
    auto f = [](int x, int y)->int{ return x > y ?  x : y; };
    // 编译器根据lambda表达式(1)生成一个类 (2)类内定义函数操作符函数 (3)返回这个类的匿名对象
    /*
        class Z4mainEUliiE_{
        public:
             int operator()(int x, int y){
                  return x > y ?  x : y;
             }
        };
        auto f = Z4mainEUliiE_{};
    */
    cout << "f的类型:" << typeid(f).name() << endl;
    cout << f(a,b) << endl; // f.operator()(a,b)

    // lambda表达式可以没有返回值类型,根据return判断
    cout << [](int x, int y) { return x+y; }(a,b) << endl;
    /*
         class X{
         public:
             auto operator()(int x, int y)->decltype(x+y){
                return x + y;
             }
         };
         cout << X{}(a,b) << endl; // cout << X{}.operator()(a,b) << endl;
    */ 

    // lambda表达式可以没有返回类型,也没有retrun语句,返回类型为void
    [](int x, int y){ cout << x << ' ' << y << endl; }(a,b);
    /*
       class XX{
       public:
            void operator()(int x, int y){
                cout << x << ' ' << y << endl;
            }
       };
       XX{}(a,b); // XX{}.operator()(a,b)
    */
    // 如果没有形参,可以省略不写
    []{ cout << "无聊" << endl;}();
    /*
         class XXXX{
         public:
              void operator(){
                cout << "无聊" << endl;
              } 
         };
         XXXX{}();  // XXXX().operator()()
     */ 
    return 0; 
} 
// lambda表达式 -- 捕获表(捕获lambda表达式外部的变量信息)
#include <iostream>
#include <typeinfo>
using namespace std;

int a = 10;

class Y{
public:
    void foo(/* Y* this */ int c = 30 ){
        cout << "-------------[]----------------" << endl;
        [](int d = 40){
            cout << "a=" << a << endl;
            cout << "b=" << b << endl;
//          cout << "c=" << c << endl; // error
            cout << "d=" << d << endl;
//          cout << "e=" << e << endl; // error
        }();
        /*
            class X{
            public:
                void operator()(int d = 40)){
                     cout << "a=" << a << endl;
                     cout << "b=" << b << endl;
                 //  cout << "c=" << c << endl; // error
                     cout << "d=" << d << endl;
                 //  cout << "e=" << this->e << endl; // error
                }
            };
            X{}();

         */

        cout << "-------------[c]----------------" << endl;
        // 捕获外部变量的值
        [c](int d = 40){ cout << "c=" << /*++*/c << endl; }();
         /* 
            class XX{
            public:
                XX(int m):c(m){} //这里的c并不是foo函数的形参,而是XX类的一个成员变量
                void operator()(int d = 40){ 
                    cout << "c=" << c << endl; // //这里的c并不是foo函数的形参,而是XX类的一个成员变量
                }
            private:
                const int c; //这里的c并不是foo函数的形参,而是XX类的一个成员变量
            };
            XX{c}(); // 这里的c是foo函数的形参c   XX(c).operator()()
         */
        cout << "-------------[&c]----------------" << endl;
        [&c](int d = 40){ cout << "c=" << ++c << endl; }();

        cout << "-------------[&c]----------------" << endl;
        [this](int d = 40){ cout << "e=" << e << endl; }();
    }

private:
    static int b;
    int e;
};

int Y::b = 20;

int main( void ){
    Y y;
    y.foo();
    return 0; 
} 

右值引用

左值 和 右值

  • 可以“取”地址的值就是左值,左值通常具名
  • 不可“取”地址的值就是右值,右值通常匿名在这里插入图片描述

左值引用 和 右值引用

  • 左值引用只能引用左值,不能引用右值
int a;
int& b = a; // OK
int c;
int& d = a + c; // ERROR
  • 右值引用只能引用右值,不能引用左值
int&& e = a + c;// OK
int&& f = a; // ERROR
  • 常左值引用,既能引用左值,也能引用右值
const int& g = a + c; // OK
const int& h = a; // OK

没有必要有常右值引用,因为常右值引用,完全可以被常左值引用替代

// 左值/右值    左值引用/右值引用
#include <iostream>
using namespace std;

int foo( ) {
    int m=888;
    return m;
}

int main( void ) {
// 当前作用域的生命期
// 具名内存-->能够取址-->左值|非常左值(无const修饰)
//                           |常左值  (有const修饰)
    int a = 10;
    int& ra = a; // ok
    const int& cra = a; // ok

    const int b = 10;
//  int& rb = b; // error
    const int& crb = b; // ok

// 语句级生命期(引用可以延长右值的生命期)
// 匿名内存-->不能取址-->右值|直接更改右值毫无意义(98/03标准给出结论)
//                           | 11标准认为给了真名就可以改

    const int& ri = 10; 
    int&& rri  = 10; 

    const int& rf = /*|888|*/foo( ); // (1)分配一块内存空间  (2)生成跳转指令
    int&& rrf = foo();
    return 0;
}
//左值引用/右值引用
#include <iostream>
using namespace std;

int main( void ) {
    int a,c;

    // 左值引用只能引用左值,不能引用右值
    int& b = a;  // ok
//  int& d = a + c; // error
   
    // 右值引用只能引用右值,不能引用左值
    int&& e = a + c; // ok
    e = 666;         // ok 通过右值引用不会丧失修改目标内存的权限
//  int&& f = a;     // error
  
    // 常左值引用(万能引用),既能引用左值,也能引用右值
    const int& g = a;     // ok
    const int& h = a + c; // ok
//  g = 666;  // error 但是通过常左值引用会丧失修改目标内存的权限
    return 0;
}

移动语义

资源的转移 代替 资源的重建

保证功能正确的情况下,做到性能提升

标签: c++

本文转载自: https://blog.csdn.net/Edu_enth/article/details/134915046
版权归原作者 InterestingFigure 所有, 如有侵权,请联系我们删除。

“15、lambda表达式、右值引用、移动语义”的评论:

还没有评论