C++(十三)现代C++ 二

引用

左值右值判断

int x = 1; x左值 1右值

int y = 3; 同上

int z = x + y 同上

特殊情况:

int a = 1;

int b = a; 此时a为左值

c++的左值指的是有一稳定内存的值或对象,该值或对象拥有稳定且较长的生命周期

a已经被赋值,占有一段稳定内存且长期存在,所以他是左值

c++的右值指的是临时对象,如函数返回,其生命周期较短  

我们可以用取地址符来判断左值还是右值,能取到地址的是左值,取不到的是右值

如,取地址a &a,程序合法,a是左值。但取地址1 &1,程序不合法,1不是右值

一些例子:

int x = 1;

int get_val()

{

    return x;

}

void set_val(int val)

{

    x = val;

}

x++; 右值, 取地址不合法

++x; 左值,取地址合法

int y = get_val();  y是左值,get_val是右值,返回的x是临时变量

set_val(5); 5传入的时候是右值,传入后在函数中val成了左值

所有的字面量除了字符串外都是右值,字符串在使用时自行开辟空间

左值引用 type &

看等号右边的值是不是左值

int & x1 = 7; 程序报错,左值引用无法绑定右值

原因左值引用x1绑定右值7,只有等号右边的值是左值才能通过

const int & x1 = 7 常量引用:左值是一个常量可以使左值引用绑定到右值上

右值引用 type &&

int && x1 = 7

可以延长右值的生命周期

int i = 0;

int && x1 = i; 程序报错,右值引用无法绑定左值

原因右值引用&&左值x1,绑定到左值i,只有等号右边的值是右值才能通过

左值引用只能引用左值绑定,右值引用只能引用右值绑定

解决上述问题

int && x1 = static_cast<int &&>(i) 强制将左值转换为右值,将i左值,转换成右值,也叫将亡值

万能引用

模板中使用&&

template<tempname T>

T foo(T && i ){}

auto res = foo(123) 

在使用该模板时,会在初始化时类型推导,在推导过程中,若初始化的对象时左值,就会推导出左值引用,右值同理。

转发函数

template<typename T>

void show_type(T tValue)

{

    std::cout << typeid(tValue).name() << std::endl;

}

template<typename T>

void show_type_forwarding(T tValue)

{

    show_type(tValue);

}

上述函数是一个转发函数,效率低下,在tValue前加上&可解决,此时为左值引用

如果要传右值,加上const,&&并且在转发的函数将参数改为static_cast<T&&>(tValue)

void show_type_forwarding(T && tValue)

{

    show_type(static_cast<T&&>(tValue));

}

std::string szString = "Hello";

show_type_forwarding(szString);

移动表达式

int x = 5;

auto func = [x](int y)->int{return x * y; };

[captures]捕获当前作用域下的列表  (Params)参数 形参

->int 返回类型 函数返回类型后置  {code} 代码块

autuo func 相当于函数指针的对象

std::cout << func(8) << std::endl;

打印结果40 5 * 8 = 40

泛型的移动语句

auto func2 = [](auto nValue){return Value};

std::cout << func2("hello") << func2(123) << std::endl;

打印hello123

异常

int x = 0;

int z = 5 / x; 程序报错 被零除或对零求模

处理异常

如果该异常可以猜测

#include<Window.h>

Windows异常:

_try

{

    int z = 5 / x;

}

_except(EXCEPTION_EXECUTE_HANDLER)

{

    std::cout << "zreo" << std::endl; 将可能发生异常的错误打印出去

}

void test() noexcept 告诉编译器该函数没有异常

{

    throw 123; 函数体中再抛出一个异常,编译器会报错

}

现代if switch语句

if语句

bool getflag()

{

    return true;

}

if(bool b = getflag(); b) 带初始化的if语句,将b初始化

{

    std::cout << b << std::endl;

 }

switch语句

switch(bool b = getflag(); b)

{

case 0:

    std::cout << 0 << std::endl;

    break;

case 1:

    std::cout << 1 << std::endl;

    break;

default:

    break

断言

包含头文件 <cassert>

断言关键字assert

断言分为运行时断言和编译器断言(静态断言),用于安全检查,括号中代码是否成立

运行时断言

char* szBuffer = nullptr;

assert(szBuffer == nullptr);

如果括号中语句符合表达式情况,程序可正常运行

如果不正确,程序不可运行

编译器断言

定义一个宏

#define FLAG 0;

static_assert(FLAG == 0); 不报错

static_assert(FLAG != 0); 报错,编译器都过不去

此时在后面加上"error:FLAG != 0",括号中表达式不符时,可以显示自己编写的错误提示

元组

包含头文件 <tuple>

元组可以返回多个不同类型

主函数外

std::tuple<int, double, std::string> getreturn()

{

    return std::male_tuple(12, 7.5, "hello")

}

主函数中

auto[x, y, z] = getreturn(); 利用auto接收

std::cout << x << std::endl;

std::cout << y << std::endl;

std::cout << z << std::endl;

此时可以正常打印 12 7.5 hello

结构体中使用:

struct

{

    int nNum = 15;

    std::string szStr = "Hello"

}obj;

auto[a, b] = obj;

std::cout << a << std::endl

std::cout << b << std::endl

打印15 Hello

别名

函数取别名

void print(int nValue)

{

    std::cout << nValue << std::endl;

}

typedef void(*fnptr)(int);

C++新式起别名

using fn = void(*)(int);

fn a = print;

a(12); 给a传值

模板取别名

需要使用容器,包含头文件map

此时一个模板

template<typename T)

using int_map = std::map(int, T)

map标准作用域下的类模板,上式将std::map(int, T)声明为int_map

主函数应用:

int_map<std::string> ins; 相当于简写原模板名了,不用写复杂的std::map(int, T)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值