首页 > 试题广场 >

说一说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表达式

【延伸阅读】

1. 增加了类型long long、unsigned long long、char16_t、char32_t 类型,新增了“原始”字符串

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;

2. 初始化列表语法

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};

3.auto 简化声明
实现自动类型推断,要求进行显示初始化,让编译器能够将变量的类型设置为初始值的类型:

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++)

4. decltype 将变量的类型声明为表达式指定的类型

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;

}

5. 返回类型后置

C++11 新增了一种函数声明语法:在函数名和参数列表后面(而不是前面)指定返回类型:

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;

}

6. 模板别名

对于冗长或复杂的标识符,如果能够创建其别名将很方便。之前,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>;

上述语句具体化模板array<T,int>,对于下述声明:

std::array<double,12> a1;

std::array<std::string,12> a2;

可将它们替换为如下声明:

arr12<double> a1;

arr12<std::string> a2;

7. nullptr 空指针

空指针是不会指向有效数据的指针。

8. 智能指针

如果在程序中使用new 从堆(自由存储区)分配内存,等到不再需要时,应使用 delete 将其释放。C++ 引入了智能指针 auto_ptr(C++98), 以帮助自动完成这个过程。智能指针是行为类似于指针的类对象。在使用时(尤其是使用 STL),需要更精致的机制,C++ 11 摒弃了 auto_ptr,并新增了三种智能指针:unique_ptr、shared_ptr 和 weak_ptr。

9. 异常规范方面的修改

以前,C++ 提供了一种语法,可用于指出函数可能引发哪些异常:

void test() throw(int);    // throw(int, double)

void test() throw();

C++ 11摒弃了异常规范,标准委员会认为,指出函数不会引发异常有一定的价值,为此添加了关键字 noexcept:

void test() noexcept;

10. 作用域内枚举

传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突。枚举名的作用域为枚举定义所属的作用域,这意味着如果在同一个作用域内定义两个枚举,它们的枚举成员不能同名。为避免这种问题,C++11 提供了一种新枚举,其枚举量的作用域为类:

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;

11. 显示转换运算符

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);    // 显示转换

12. 类内成员初始化

class Person {

    string name = "zs";

    int age {22};    // int age = 22;    

public:

    Person(){}

    Person(string s, int a) : name(s), age(a) {};

}

可以使用等号或大括号版本的初始化,但不能使用圆括号版本的初始化。如果构造函数在成员初始化列表中提供了相应的值,这些默认值将被覆盖。

13. 右值引用

传统的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;

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);

新增右值引用的主要目的之一是实现移动语义,让库设计人员能够提供有些操作的更有效实现。


编辑于 2021-09-17 11:28:21 回复(0)
auto类型推导
declatype类型推导
四种cast类型转换
智能指针
try_catch抛出异常
lamada表达式
发表于 2022-04-04 18:44:38 回复(0)
C++11的新特性包括但不限于:自动类型推断、Lambda表达式、范围for循环、nullptr关键字、智能指针、右值引用、移动语义、多线程支持等。
发表于 2024-01-06 09:41:54 回复(0)