说一说C++11 的新特性有哪些
【得分点】
智能指针、右值引用、移动语义、Lambda表达式
【参考答案】
标准回答
C++ 11 的新特新有:
1. 新增了类型long long 和 unsigned long long,以支持 64 位(或更宽)的整型,新增了类型 char16_t 和 char32_t,以支持 16 位和 32 位的字符表示;还新增了”原始“字符串。
2. 初始化列表语法
3. auto 简化声明
4. decltype 将变量的类型声明为表达式指定的类型
5. 返回类型后置
6. 模板别名
7. nullptr 空指针
8. 智能指针
9. 异常规范方面的修改
10. 作用域内枚举
11. 显示转换运算符
12. 类内成员初始化
13. 右值引用
14. 移动语义
15. Lambda表达式
【延伸阅读】
cout << "C:\Program Files (x86)\Application Verifier" << endl; cout << R"(C:Program Files (x86)Application Verifier)" << endl; cout << R"+*(C:Program Files (x86)"Application Verifier)+*" << endl;
cout << "C:\Program Files (x86)\Application Verifier" << endl;
cout << R"(C:Program Files (x86)Application Verifier)" << endl;
cout << R"+*(C:Program Files (x86)"Application Verifier)+*" << endl;
C++ 11 扩大了用大括号括起的列表(初始化列表)的适用范围,使其可用于所有内置类型和用户定义的类型(即类对象)。使用初始化列表时,可添加等号(=),也可不添加:
int x = {5}; double y {2.75}; short quar[5] {1, 2, 3, 4, 5}; int * ar = new int [4] {2, 3, 4, 5}; class Stump { private: int roots; double weight; public: Stump(int r, double w) : roots(r), weight(w) {} }; Stump s1(3, 15.6); Stump s2{5, 43.4}; Stump s3 = {4, 32.1};
int x = {5};
double y {2.75};
short quar[5] {1, 2, 3, 4, 5};
int * ar = new int [4] {2, 3, 4, 5};
class Stump {
private:
int roots;
double weight;
public:
Stump(int r, double w) : roots(r), weight(w) {}
};
Stump s1(3, 15.6);
Stump s2{5, 43.4};
Stump s3 = {4, 32.1};
auto a = 12; auto pt = &a; double fm(double a, int b) { return a + b; } auto pf = fm;
auto a = 12;
auto pt = &a;
double fm(double a, int b) {
return a + b;
}
auto pf = fm;
简化模板声明
for(std::initializer_list<double>::iterator p = il.begin(); p != il.end(); p++) for(auto p = il.begin(); p != il.end(); p++)
for(std::initializer_list<double>::iterator p = il.begin(); p != il.end(); p++)
for(auto p = il.begin(); p != il.end(); p++)
decltype 将变量的类型声明为表达式指定的类型。
decltype(expression) var;
decltype(x) y; // 让y的类型与x相同,x是一个表达式
double x; int n; decltype(x*n) q; decltype(&x) pd; template<typename T, typename U> void ef(T t, U u) { decltype(T*U) tu; }
double x;
int n;
decltype(x*n) q;
decltype(&x) pd;
template<typename T, typename U>
void ef(T t, U u) {
decltype(T*U) tu;
C++11 新增了一种函数声明语法:在函数名和参数列表后面(而不是前面)指定返回类型:
double f1(double, int); auto f2(double, int) -> double; // -> double 称为后置返回类型,auto是一个占位符,表示后置返回类型提供的类型
double f1(double, int);
auto f2(double, int) -> double;
// -> double 称为后置返回类型,auto是一个占位符,表示后置返回类型提供的类型
有一个相关的问题是decltype 本身无法解决的:
template<typename T1, typename T2> ??? gt(T1 x, T2 y) { // ... return x + y; } template<typename T1, typename T2) auto eff(T1 x, T2 y) -> decltype(x*y){ // decltype 在参数声明后面,因此x和y位于作用域内,可以使用 // ... return x * y; }
template<typename T1, typename T2>
??? gt(T1 x, T2 y) {
// ...
return x + y;
template<typename T1, typename T2)
auto eff(T1 x, T2 y) -> decltype(x*y){
// decltype 在参数声明后面,因此x和y位于作用域内,可以使用
return x * y;
对于冗长或复杂的标识符,如果能够创建其别名将很方便。之前,C++ 提供了 typedef:
typedef std::vector<std::string>::iterator itType;
C++ 11 提供了另一种创建别名的语法:
using itType = std::vector<std::string>::iterator;
差别在于,这种方式也可以用于模板部分具体化,但typedef 不能:
template<typename T> using arr12 = std::array<T,12>;
template<typename T>
using arr12 = std::array<T,12>;
上述语句具体化模板array<T,int>,对于下述声明:
std::array<double,12> a1; std::array<std::string,12> a2;
std::array<double,12> a1;
std::array<std::string,12> a2;
可将它们替换为如下声明:
arr12<double> a1; arr12<std::string> a2;
arr12<double> a1;
arr12<std::string> a2;
空指针是不会指向有效数据的指针。
如果在程序中使用new 从堆(自由存储区)分配内存,等到不再需要时,应使用 delete 将其释放。C++ 引入了智能指针 auto_ptr(C++98), 以帮助自动完成这个过程。智能指针是行为类似于指针的类对象。在使用时(尤其是使用 STL),需要更精致的机制,C++ 11 摒弃了 auto_ptr,并新增了三种智能指针:unique_ptr、shared_ptr 和 weak_ptr。
以前,C++ 提供了一种语法,可用于指出函数可能引发哪些异常:
void test() throw(int); // throw(int, double) void test() throw();
void test() throw(int); // throw(int, double)
void test() throw();
C++ 11摒弃了异常规范,标准委员会认为,指出函数不会引发异常有一定的价值,为此添加了关键字 noexcept:
void test() noexcept;
传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突。枚举名的作用域为枚举定义所属的作用域,这意味着如果在同一个作用域内定义两个枚举,它们的枚举成员不能同名。为避免这种问题,C++11 提供了一种新枚举,其枚举量的作用域为类:
enum class egg {Small, Medium, Large, Jumbo}; enum class t_shirt {Small, Medium, Large, Xlarge};
enum class egg {Small, Medium, Large, Jumbo};
enum class t_shirt {Small, Medium, Large, Xlarge};
也可以使用关键字struct 代替 class,新枚举要求进行显示限定,以免发生名称冲突:
egg choice = egg::Large; t_shirt Floyd = t_shirt::Large;
egg choice = egg::Large;
t_shirt Floyd = t_shirt::Large;
C++很早就支持对象自动转换,但是自动类型转换可能导致意外转换的问题,为了解决这个问题,C++引入了关键字 explicit,以禁止单参数构造函数导致的自动转换:
class Plebe{ Plebe(int); explicit Plebe(double); // ... }; Plebe a, b; a = 5; b = 0.5; // 不允许 b = Plebe(0.5); // 显示转换 C++11 拓展了 explicit 的这种用法,使得可以对转换函数做类似的处理: class Plebe { operator int() const; explicit operator double() const; // ... }; Plebe a, b; int n = a; double x = b; // 不允许 x = double(b); // 显示转换
class Plebe{
Plebe(int);
explicit Plebe(double);
Plebe a, b;
a = 5;
b = 0.5; // 不允许
b = Plebe(0.5); // 显示转换
C++11 拓展了 explicit 的这种用法,使得可以对转换函数做类似的处理:
class Plebe {
operator int() const;
explicit operator double() const;
int n = a;
double x = b; // 不允许
x = double(b); // 显示转换
class Person { string name = "zs"; int age {22}; // int age = 22; public: Person(){} Person(string s, int a) : name(s), age(a) {}; }
class Person {
string name = "zs";
int age {22}; // int age = 22;
Person(){}
Person(string s, int a) : name(s), age(a) {};
可以使用等号或大括号版本的初始化,但不能使用圆括号版本的初始化。如果构造函数在成员初始化列表中提供了相应的值,这些默认值将被覆盖。
传统的C++ 引用(现在称为左值引用)使得标识符关联到左值。左值是一个表示数据的表达式(如变量名或解除引用的指针),程序可获取其地址。最初,左值可出现在赋值语句的左边,但修饰符 const 的出现使得可以声明这样的标识符,即不能给它赋值,但可获取其地址:
int n; int * pt = new int; const int b = 101; int & rn = n; int & rt = *pt; const int & rb = b; const int & rb = 10;
int * pt = new int;
const int b = 101;
int & rn = n;
int & rt = *pt;
const int & rb = b;
const int & rb = 10;
C++ 11 新增了右值引用(rvalue reference),这种引用可指向右值(即可出现在赋值表达式右边的值),但不能对其应用地址运算符。右值包括字面常量(C-风格字符串除外,它表示地址)、诸如 x + y 等表达式以及返回值的函数(条件是该函数返回的不是引用),右值引用使用 && 声明:
int x = 10; int y = 23; int && r1 = 13; int && r2 = x + y; double && r3 = std::sqrt(2.0);
int x = 10;
int y = 23;
int && r1 = 13;
int && r2 = x + y;
double && r3 = std::sqrt(2.0);
新增右值引用的主要目的之一是实现移动语义,让库设计人员能够提供有些操作的更有效实现。
这道题你会答吗?花几分钟告诉大家答案吧!
扫描二维码,关注牛客网
下载牛客APP,随时随地刷题
【得分点】
智能指针、右值引用、移动语义、Lambda表达式
【参考答案】
标准回答
C++ 11 的新特新有:
1. 新增了类型long long 和 unsigned long long,以支持 64 位(或更宽)的整型,新增了类型 char16_t 和 char32_t,以支持 16 位和 32 位的字符表示;还新增了”原始“字符串。
2. 初始化列表语法
3. auto 简化声明
4. decltype 将变量的类型声明为表达式指定的类型
5. 返回类型后置
6. 模板别名
7. nullptr 空指针
8. 智能指针
9. 异常规范方面的修改
10. 作用域内枚举
11. 显示转换运算符
12. 类内成员初始化
13. 右值引用
14. 移动语义
15. Lambda表达式
【延伸阅读】
2. 初始化列表语法
C++ 11 扩大了用大括号括起的列表(初始化列表)的适用范围,使其可用于所有内置类型和用户定义的类型(即类对象)。使用初始化列表时,可添加等号(=),也可不添加:
3.auto 简化声明简化模板声明
4. decltype 将变量的类型声明为表达式指定的类型
decltype 将变量的类型声明为表达式指定的类型。
decltype(expression) var;
decltype(x) y; // 让y的类型与x相同,x是一个表达式
5. 返回类型后置
C++11 新增了一种函数声明语法:在函数名和参数列表后面(而不是前面)指定返回类型:
有一个相关的问题是decltype 本身无法解决的:
6. 模板别名
对于冗长或复杂的标识符,如果能够创建其别名将很方便。之前,C++ 提供了 typedef:
C++ 11 提供了另一种创建别名的语法:
差别在于,这种方式也可以用于模板部分具体化,但typedef 不能:
上述语句具体化模板array<T,int>,对于下述声明:
可将它们替换为如下声明:
7. nullptr 空指针
空指针是不会指向有效数据的指针。
8. 智能指针
如果在程序中使用new 从堆(自由存储区)分配内存,等到不再需要时,应使用 delete 将其释放。C++ 引入了智能指针 auto_ptr(C++98), 以帮助自动完成这个过程。智能指针是行为类似于指针的类对象。在使用时(尤其是使用 STL),需要更精致的机制,C++ 11 摒弃了 auto_ptr,并新增了三种智能指针:unique_ptr、shared_ptr 和 weak_ptr。
9. 异常规范方面的修改
以前,C++ 提供了一种语法,可用于指出函数可能引发哪些异常:
C++ 11摒弃了异常规范,标准委员会认为,指出函数不会引发异常有一定的价值,为此添加了关键字 noexcept:
10. 作用域内枚举
传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突。枚举名的作用域为枚举定义所属的作用域,这意味着如果在同一个作用域内定义两个枚举,它们的枚举成员不能同名。为避免这种问题,C++11 提供了一种新枚举,其枚举量的作用域为类:
也可以使用关键字struct 代替 class,新枚举要求进行显示限定,以免发生名称冲突:
11. 显示转换运算符
C++很早就支持对象自动转换,但是自动类型转换可能导致意外转换的问题,为了解决这个问题,C++引入了关键字 explicit,以禁止单参数构造函数导致的自动转换:
12. 类内成员初始化
可以使用等号或大括号版本的初始化,但不能使用圆括号版本的初始化。如果构造函数在成员初始化列表中提供了相应的值,这些默认值将被覆盖。
13. 右值引用
传统的C++ 引用(现在称为左值引用)使得标识符关联到左值。左值是一个表示数据的表达式(如变量名或解除引用的指针),程序可获取其地址。最初,左值可出现在赋值语句的左边,但修饰符 const 的出现使得可以声明这样的标识符,即不能给它赋值,但可获取其地址:
C++ 11 新增了右值引用(rvalue reference),这种引用可指向右值(即可出现在赋值表达式右边的值),但不能对其应用地址运算符。右值包括字面常量(C-风格字符串除外,它表示地址)、诸如 x + y 等表达式以及返回值的函数(条件是该函数返回的不是引用),右值引用使用 && 声明:
新增右值引用的主要目的之一是实现移动语义,让库设计人员能够提供有些操作的更有效实现。