牛客网C++面经 C++11

请问C++11有哪些新特性?

  • auto关键字:编译器可以根据初始值自动推导出类型。但是不能用于函数传参以及数组类型的推导
  • nullptr关键字:nullptr是一种特殊类型的字面值,它可以被转换成任意其它的指针类型;而NULL一般被宏定义为0,在遇到重载时可能会出现问题。
  • 智能指针:C++11新增了std::shared_ptr、std::weak_ptr等类型的智能指针,用于解决内存管理的问题。
  • 初始化列表:使用初始化列表来对类进行初始化
  • 右值引用:基于右值引用可以实现移动语义和完美转发,消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率
  • atomic原子操作用于多线程资源互斥操作
  • 新增STL容器array以及tuple

请你详细介绍一下C++11中的可变参数模板、右值引用和lambda这几个新特性。

可变参数模板:

  • C++11的可变参数模板,对参数进行了高度泛化,可以表示任意数目、任意类型的参数,其语法为:在class或typename后面带上省略号”。

例如:

Template<class ... T>
void func(T ... args)
{
cout<<”num is”<<sizeof ...(args)<<endl;
}
  • func();//args不含任何参数
  • func(1);//args包含一个int类型的实参
  • func(1,2.0)//args包含一个int一个double类型的实参
  • 其中T叫做模板参数包,args叫做函数参数包

省略号作用如下:

  • 1)声明一个包含0到任意个模板参数的参数包
  • 2)在模板定义得右边,可以将参数包展成一个个独立的参数
  • C++11可以使用递归函数的方式展开参数包,获得可变参数的每个值。通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数。例如:
#include using namespace std;

// 最终递归函数

void print()
{
cout << "empty" << endl;
}

// 展开函数
template void print(T head, Args... args)
{
cout << head << ","; print(args...);
}
int main()
{
print(1, 2, 3, 4); return 0;
}
  • 参数包Args ...在展开的过程中递归调用自己,每调用一次参数包中的参数就会少一个,直到所有参数都展开为止。当没有参数时就会调用非模板函数printf终止递归过程。

补充

#include <iostream>
#include <vector>

template <class T>
class Stack{
private:
    std::vector<T> elements;//元素
public:
    void push(T const&);//入栈
    void pop();//出栈
    T top() const;//返回栈顶元素
    bool empty() const{//如果为空返回真
        return elements.empty();
    }
};

template<class T>
void Stack<T>::push(const T &elem) {
    //追加元素的副本
    elements.template emplace_back(elem);
}
template<class T>
void Stack<T>::pop() {
    if (elements.empty()){
        throw std::out_of_range("Stack<>::pop():empty stack");
    }
    //删除元素
    elements.pop_back();
}

template <class T>
T Stack<T>::top() const {
    if (elements.empty()){
        throw std::out_of_range("Stack<>::top():empty stack");
    }
    //返回第一个元素的副本
    return elements.back();
}

int main(int argc,char* argv[])
{
    try {
        Stack<int> int_stack{};
        Stack<std::string> string_stack{};
        //操作 int 类型的栈
        int_stack.push(7);
        std::cout << int_stack.top() << std::endl;
        //操作 string 类型的栈
        string_stack.push("hello");
        std::cout << string_stack.top() << std::endl;
        string_stack.pop();
        string_stack.pop();
    } catch (std::exception const&ex) {
        std::cerr << "Exception:" << ex.what() << std::endl;
        return -1;
    }
    return 0;
}

右值引用:

  • C++中,左值通常指可以取地址,有名字的值就是左值,而不能取地址,没有名字的就是右值。而在指C++11中,右值是由两个概念构成,将亡值和纯右值。纯右值是用于识别临时变量和一些不跟对象关联的值,比如1+3产生的临时变量值,2、true等,而将亡值通常是指具有转移语义的对象,比如返回右值引用T&&的函数返回值等。
  • C++11中,右值引用就是对一个右值进行引用的类型。由于右值通常不具有名字,所以我们一般只能通过右值表达式获得其引用
  • 基于右值引用可以实现转移语义和完美转发新特性。
  • 参见原文

Lambda表达式

  • Lambda表达式定义一个匿名函数,并且可以捕获一定范围内的变量,其定义如下:
  • [capture](params)mutable->return-type{statement}
  • [capture]:捕获列表,捕获上下文变量以供lambda使用。同时[]是lambda寅初复,编译器根据该符号来判断接下来代码是否是lambda函数。
  • (Params):参数列表,与普通函数的参数列表一致,如果不需要传递参数,则可以连通括号一起省略。
  • mutable是修饰符,默认情况下lambda函数总是一个const函数,Mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略。
  • ->return-type:返回类型是返回值类型
  • {statement}:函数体,内容与普通函数一样,除了可以使用参数之外,还可以使用所捕获的变量。
  • Lambda表达式与普通函数最大的区别就是其可以通过捕获列表访问一些上下文中的数据。其形式如下:

  • Lambda的类型被定义为“闭包”的类,其通常用于STL库中,在某些场景下可用于简化仿函数的使用,同时Lambda作为局部函数,也会提高复杂代码的开发加速,轻松在函数内重用代码,无须费心设计接口。
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值