c++基础——c++11中的新特性

来源:互联网 发布:七天网络注册登录查分 编辑:程序博客网 时间:2024/06/06 03:23

1. 新增关键词nullptr。

新增的nullptr是用来替代0或者NULL,来表示指向空(no value)的指针。

下面是一个例子:

void func(int i) {cout << "func(int i)" << endl;}void func(void *p) {cout << "func(void *p)" << endl;}int main() {int i = NULL;int j = 0;std::nullptr_t p = nullptr;func(i);func(j);func(p);}
运行的结果:

func(int i)func(int i)func(void *p)
nullptr的类型是std::nullptr_t,定义于<cstddef>。


2. 增加auto来判断变量或对象类型。

auto可以用在各种类型上,包括lambda上也可以用。

但是auto必须要初始化操作,因为它需要初始化值来推导。


3. 使用{}引入“一致性初始化",或者也称为“列表初始化”。

列表初始化例子:

int main() {int i{};cout << "i = " << i << endl;//会有初始化,打印0int j = {};cout << "j = " << j << endl;//会有初始化,打印0//int k = { 2.0 };//报错,因为有narrowingvector<int> v1 = { 1, 2, 3 };vector<int> v2{ 4, 5, 6 };for (auto a = v1.begin(); a != v1.end(); a++) {cout << *a << endl;}for (auto a = v2.begin(); a != v2.end(); a++) {cout << *a << endl;}}
以上是基本类型的列表初始化(vector应该不算)。

但是有一个问题,i{}和j = {}是不是有什么差别?

对于基本类型,应该没有差别吧,因为本来也不涉及到构造函数。对于类的话,应该有通用的指明初始值列的构造函数。这需要使用到class template std::initializer_list<>。

下面是类的列表初始化示例:

class CLS {private:int age;int height;public:CLS(int a, int h) : age(a), height(h){cout << "CLS(int a, int h)" << endl;}CLS(std::initializer_list<int> vals) {cout << "CLS(std::initializer_list<int> vals)" << endl;auto a = vals.begin();age = *a;++a;height = *a;}void print(void) {cout << "age : " << age << endl;cout << "height : " << height << endl;}};int main() {CLS c1(1, 2);c1.print();CLS c2{ 3, 4 };c2.print();CLS c3 = { 5, 6 };//调用的构造函数同c2{3, 4}c3.print();return 0;}
运行的结果:

CLS(int a, int h)age : 1height : 2CLS(std::initializer_list<int> vals)age : 3height : 4CLS(std::initializer_list<int> vals)age : 5height : 6


4. c++11引入一种崭新的for循环形式,其实就是foreach循环。

下面是例子:

int main() {for (int a : {1, 2, 3, 4}) {cout << a << endl;}vector<int> v{ 5, 6, 7, 8 };for (auto& a : v) {//使用引用,就可以修改至,否则就不能修改;a *= 2;}for (auto a : v) {cout << a << endl;}}


5. std::move,右值引用。

这个比较麻烦,这里不细讲了。


6. 关键字noexcept。

noexcept指明了函数不会抛出异常,或者它可能也或抛出异常,但是我们也处理不了,就不用管异常处理的事情了。

需要说明编译的时候是不会去管noexcept函数里面有没有抛出异常的,只是在运行时,如果一个noexcept函数抛出了异常,程序就会调用ternimate来终止程序本身。

另外noexcept也是一个运算符,后面接一个bool的参数:

void foo(void) noexcept;void foo(void) noexcept(true);
上面两个函数是等价的,不过在vs中好像构成了重载,就是说两个都可以存在,编译能够通过。


7. 关键字constexpr。

constexpt关键字让表达式在编译器就是常量,因此可以用在一些只能是常量的地方。比如下面的例子:

constexpr int square(int x) {return x * x;}int main() {int a[square(3)]{};return 0;}
下面的例子中就移动要用constexpr来声明square,否在main()中的a数组定义时会报错。


8. lambda表达式。

它的格式有两种:

[...] {...}
还有更复杂一些的:

[...] (...) mutable throw语句 ->retType {...}
多出来的部分都是可选的。

[]部分称为capture,其实就是从包含该lambda表达式的函数中的参数,它们传到lambda表达式的方式两种,一种是传值,一种是传引用。用=来表示传值,或者不写也表示传值;用&来表示传引用,传引用的时候要注意的是这个值会在不同的阶段改变,随之而来的是lambda表达式的这个变量也变了。

下面是几个例子:

int main() {auto l = [] {return 42;//不用指定类型,那么编译器就自动推断,比如这里就是int};//分号不能忘cout << l() << endl;//l后面的()不能忘,因为它是函数对象,打印42/*l = []() -> double {return 42;};*/ //两个lambda类型不一样,所以不能这么用auto ll = []() -> double {//指定了返回类型,这个时候就一定要把()也写上,不然会报错return 42;};cout << ll() << endl;//打印42int x = 0;int y = 0;auto lll = [x, &y]() {cout << "x: " << x << " " << "y: " << y << endl;++y;//++x;这么写直接报错};x = y = 1;lll();//打印x: 0 y: 1,注意前面的y=1有生效。lll();//打印x: 0 y: 2//使用mutable可以让传值变量也可以改变:int z = 0;auto llll = [z]() mutable {++z;cout << "z: " << z << endl;};z = 100;//但是无论是不是mutable,这个赋值对于llll都没有用llll();//打印z: 1}

9. 关键字decltype。

这个关键字让编译器能够得到表达式的类型。例如:

int main() {std::map<std::string, float> coll;decltype(coll)::value_type elem;}


10. c++11新增的类型:char16_t / char32_t / long long / unsigned long long / std::nullptr_t。


11. c++会在main()中定义一个隐式的return 0。

所有main中不写return也可以。

0 0
原创粉丝点击