C++ 11特性理解

结合C++ PRIMER 与个人见解编写,如有错误,请指出。

1.1 C++ 11

C++ PRIMER (第五版 中文版)作为此部分的参考资料与新特性顺序。

1.1.1 long long数据类型

8个字节的长度,虽然表示的数很大,但是也需要考虑溢出,在数据不需要考虑负数的情况下,还是需要添加unsignd来扩大数据的范围(准确的说,正数的范围)

1.1.2 nullptr常量

在C++中,null关键字本质为int数据类型的“0”,在表示空指针的情况下,使用null并不能准确的表示一个空的指针,其大小也非指针大小(这里需要看机器是64位/32位来确定指针大小),使用nullptr可以更准确的表示一个空指针,其可以转换为任意类型的其他指针。

1.1.3列表初始化

这种初始化有一种重要的特征,初始值存在丢失信息的风险时,会报错,可以用在需要避免隐形数据转换的场景中(防止不经意间的数据转换)。

要注意初始化与赋值是不同的两个概念,赋值会将当前值擦除后代替,但是初始化不会产生擦除的操作

1.1.4 constexpr变量

在变量前添加constexpr类型,来使编译器确定其值是否为常量表达式。

声明为constexpr类型的变量,其值必须为常量。

也可以将其用来定义constexpr函数,这样就可以利用函数在编译器就确定值,减少了在运行期的运算成本。

1.1.5 类型别名声明

如:using SystemControl = SC;

在使用类型函数指针,较为复杂的类型时,可以增加代码的可读性,可维护性

1.1.6 auto类型指示符(类型推导)

可以自动的推导出表达式的数据类型,但是要注意在有const类型修饰变量其在推导时,会忽略顶层const,但是底层的const会得到保留。

如果希望保留被推导对象的顶层const,就需要显式的指出:

        const auto target = TopConstTarget;

auto定义的变量必须具有初始值,也就是说,自动推导必须要有可以推导的对象。

auto现在已经可以使用在函数返回值上:(C++ 14)

auto func(int inputA,int inputB)

{

        return inputA+inputB;

}

不用需要注意的是,如果返回值设置为:

return {12,13,1,4,15,16,17};

只会被推导为 initializer_list,而不是预想中的vector或者list。

在使用引用来作为被推导对象时,其不会推导出引用,被推导对象实质为被引用对象。

1.1.7 decltype类型指示符(类型推导)

与auto使用方法不同,其也需要表达式来推导数据类型,但是不会使用被推导对象来初始化对象。

decltype(expr) si = expr;

在处理顶层const与引用的使用,其处理方式也和auto不同,会推导出顶层const与引用。

在被推导对象是函数的时候,会选择其返回值来作实际被推导对象,在此过程中,不会产生函数的调用。

需要注意的是括号,decltype(expr)在推导的时候,只有expr是引用的时候,才会推导出引用,但是decltype((expr))推导出的永远是引用,就会需要初始化这个引用。

还有需要注意的是表达式的推导:

int a=0,b=0;

decltype(a = b) d = a;

这里 a = b 表达式的数据类型为int&,如果等号两边的数据类型变化,就会是那个数据类型的引用。

所以上式 d会是a的引用。

1.1.8 基于范围的for语句

vector<int> vec;

//此处向vec中填入数据(懒得写了)

for(auto target : vec)

{

        cout<<target<<endl;

}

上述代码可以输出所有vec中的数据,但是要注意,这里的target获得的值是拷贝的值,因此无法通过修改target来修改vec中的值,需要利用引用来修改:

for(auto &target : vec)

{

        cout<<target<<endl;

}

这样便可以通过target来修改,同时使用引用可以避免拷贝产生的多余性能消耗。

注:不应该在范围for中修改遍历序列的大小。

在不修改target的值的时候,最好使用const来修饰,防止数据的修改。

1.1.9容器的cbegin和cend函数

STL容器一般都会有 begin(),end()与cbegin()和cend()函数,

cend与cbegin的c表示const,获取的迭代器为const_iterator

这样获得的数据就会是常量引用,不会产出有拷贝或移动产生多余的性能消耗。

也便于对STL中的只读算法进行操作。

1.1.10标准库中的begin() 与end()函数

与容器中的函数很像,但是这两个是两个东西,用于计算获得指针的头指针与尾指针。

使指针的操作更安全,更简单。

begin()获得指向首元素的指针

end()获得指向末尾对象的下一位的指针

可以方便的构筑出一个范围来进行循环。

1.1.11用大括号包围的值列表赋值

可以使用花括号包裹的列表来进行赋值(类似列表初始化)

vector<int> vec;

vec = { 12,45,23,56,78,89,15,59};

可以增加代码的可读性,不过要注意在使用过程中可能出现的隐式类型转换。

1.1.12列表初始化返回值

vector<string> func ( )

{

        int i=0;

        if(i == 0)

        {

                return {“this ”,”is ”,”null”};

        }

        else

        {

                return {“not ”,”null”};

        }

}

可以使用返回值进行返回类型的初始化,这里便是利用返回值对vector<string>进行了初始化。

1.1.13 constexpr 函数

constexpr 函数指的是可以用于常量表达式中的函数,定义的方式与普通函数的方式相同,但还是有一些不同:

函数的形参,返回值类型都需要是字面值类型(算术类型,引用,指针),且只能有一条return语句。

函数的返回值可以不是常量,但必须是字面值类型,因此可以返回指针。

1.1.14 委托构造函数

委托构造函数可以使用类内的其他构造函数在完成他自己的初始化过程

class projectMy

{

private:

        string str1;

        float fou1;

        double dou1;

public:

        projectMy (string str,float fou,double dou):str1(str),fou1(fou),dou1(dou){}

        projectMy ():projectMy (“ssss”,0,0){}

};

委托构造函数会自行寻找匹配形参的构造函数,

委托构造函数也可以委托其他的委托构造函数。

1.1.15右值引用

可以用来获取即将被销毁的对象,诸如表达式计算结果。

为了支持移动操作而创建。

1.1.16 标准库move函数

对其应该显式的使用 std::move,来防止冲突。

相当于告诉编译器,我需要将一个左值按照右值来进行操作。

通过std::move(),可以避免不必要的拷贝操作。

在创建某一些对象的时候,可以使用已有的对象来进行移动创建,这样创建的过程中不会产生拷贝操作,减少了内存的使用,提高了资源的利用效率。

1.1.17 移动构造函数

使用一个已有的类对象来创建一个类对象,创建的类对象会使用已有对象的内存空间来进行初始化操作,中间不会有诸如拷贝构造函数会产生的拷贝操作,可以有效减少内存的使用。具有较大内存空间的类对象,使用移动构造函数可以有效的提高程序的效率。

但是要注意的是,已有类对象后续不能再使用,对象已被销毁。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nameless_233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值