常用的C++11特性(面试易考)

大二的时候看过《C++Primer》,了解过C++11,因此就在简历上写上了解C++11,结果就是频频被问到有关C++11。。。发现自己答的并不算太好~

因此,简单总结一下,我在找实习的过程被问到的C++11特性。


1. nullptr

注意在C++中NULL仅仅是define NULL 0的一个宏定义,因此,有时候会产生歧义

比如f(char*)和f(int),参数传NULL的话到底该调用哪个?事实上,在VS下测试这样的函数重载会优先调用f(int),但是f(char *)也是正确的,因此C++引入nullptr来避免这个问题。

更多请参考nullptr, NULL

2. auto, decltype

两者支持类型推导,获取

int a = 0;
decltype(a) b = 3;
cout << b << endl;

3.范围for

常常和auto结合

比如

int arr[] = {1,2,3,4,5};
for(int& e : arr) 
{
  e = e*e;
}

4.智能指针

基于RAII原则,引入shared_ptr, unique _ptr等等,具体可参见智能指针和RAII

5. 新增容器

  1. array最早是在boost中出现:http://www.boost.org/doc/libs/1_61_0/doc/html/array.html
    当时的初衷是希望提供一个在栈上分配的,定长数组,而且可以使用stl中的模板算法。

  2. unordered_map unordered_set
    同样是来至boost的组件:http://www.boost.org/doc/libs/1_61_0/doc/html/unordered.html
    在早期的标准库stl中是只有红黑树map,而没有hash map的。
    所以boost提供了unordered这个组件,并且在c++11中进入了标准库。
    unordered_ map提供了和map类似的接口,只是map是有序,而unordered_map因为采用hash map的数据结构,所以是无序的。

    关于unordered_map和map的使用场景:

    1. 查找速度:unordered_map底层是一个hash _ table,一般来说hash函数,hash冲突解决的好,可以达到O(1),map底层是一棵红黑树,效率大概是O(logn)
    2. 内存问题,unordered_map是利用了空间换时间,哈希表的元素越少,hash冲突可能性也就越少,效-也就越接近于O(1),但是这样一来,它的空间利用率也越小;所以一般来说,哈希表的装填因子大概在0.7-0.8。

6.右值引用,移动构造函数

分清楚什么是左值和右值,一个比较简易的方法就是能否取地址,能取地址的则为左值。

为什么引入右值机制?主要是为了效率,在

右值一般为临时变量,字面常量也属于右值,因为临时变量往往在后面不可使用或者说不再使用,因此,我们可以steal窃取他们的资源。

我们看一个例子:

class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    A(const A&)
    {
        cout << "A(const A&)" << endl;
    }


};

vector<A> Get()
{
    vector<A> tmp;
    tmp.push_back(A());
    cout << "Get end" << endl << endl;
    return tmp;
}

int main()
{
    vector<A> v;
    v = Get();

    return 0;
}

在C99标准下编译后结果如下:

这里写图片描述

在C++11标准下编译后结果如下:

这里写代码片

为什么会这样?

这是因为:

对于Get函数,它会返回一个临时vector < A> 对象,当main函数中,执行到v = Get()时候,它会将v
中现有成员都删除,然后将这个临时对象里面所有内容都拷贝到v中,最后析构这个临时对象。

我们知道拷贝复制的代价还是很大,对于这种情况,我们完全可以直接将v中资源和这个临时对象中的资源交换,然后再删除临时对象,这样就避免复制操作,提高了效率。

右值引用必须绑定在右值上,但是我们可以通过std::move函数“绑定左值”

右值引用因为绑定对象即将被销毁,意味着没有人会继续访问他们,所以就可以把他们(的资源)steal过来。

虽然不能将右值引用绑在左值上,但通过利用utility头文件新增的函数模板move,它返回传入对象的右值引用,可以达到 steal的效果。

int &&rr3 = std::move(rr2); // ok
再提醒:一旦使用了move,编译器就默认传入对象已经不打算使用了,是可以被销毁的,move之后该对象的值已经不确定,不要再访问。还有由于对象偷取与复制的差别巨大,不注意会产生非常难定位的bug,所以所有使用move的地方一定要使用全称std::move,给大家以提醒。(其实c++11在algorithm头文件也新增了一个move,参数与意义都与此截然不同)。

移动构造函数等

  1. move构造函数

对象可以被复制构造,满足条件场景下,自然也就可以被“剪切”构造。move构造函数就用于此,它也属于copy-control系列函数,后者的5个成员现在更新为:拷贝构造函数,复制性质的赋值运算符,move构造函数,move性质的赋值运算符,析构函数。

class base
{
public:
int* p;
base():{p = new(…);}
~base(){delete p;}
base(base&& ref):p(ref.p){ref.p = nullptr;}

};
新创建对象的指针p接管了来源对象指针p所持有的资源,并将后者置空。特别注意move构造函数一定要来源对象内部存储资源的变量设置正确的状态,如指针置空等,避免来源对象析构时内存误释放。

move语义不仅仅用于右值,也用于左值。标准库提供了std::move方法,将左值转换成右值。因此,对于swap函数,我们可以这样实现:

template<class T>
void swap(T& a, T& b)
{
    T temp(std::move(a));
    a = std::move(b);
    b = std::move(temp);
}

参考:
http://www.cnblogs.com/TianFang/archive/2013/01/26/2878356.html

http://www.cnblogs.com/virusolf/p/5604394.html

C++11 中值得关注的几大变化(详解)

发布了96 篇原创文章 · 获赞 119 · 访问量 17万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章