【c/c++】C++11中的新特性
说明
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,定义于
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 v1 = { 1, 2, 3 };vector 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 vals) {cout << "CLS(std::initializer_list 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 : 1
height : 2
CLS(std::initializer_list vals)
age : 3
height : 4
CLS(std::initializer_list vals)
age : 5
height : 6
4. c++11引入一种崭新的for循环形式,其实就是foreach循环。
下面是例子:
int main() {for (int a : {1, 2, 3, 4}) {cout << a << endl;}vector 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 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也可以。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
