C++11杂记

转载出处:http://blog.csdn.net/sharing_li/article/details/50418864

1__func__ 返回所在函数的名称

2、定义了与预处理指令#pragma功能相同的操作符_Pragma,使用格式:_Pragma(字符串字面量)。#pragma once 等价于 _Pragma(“once”)。#pragma不能用于宏,_Pragma能用于宏,更灵活。

3、为了更好的支持Unicode,支持宽窄字符串的连接等。

4、静态断言static_assert(返回值为bool的表达式,输出的字符串类信息)。表达式必须是在编译时期可以计算的表达式。

5、noexcept修饰的函数不会抛出异常,用noexcept替换throw()。noexcept修饰符有两种形式:1、void func() noexcept; 2、void func() noexcept(常量表达式)。常量表达式的结果会被转换成一个bool类型的值,为true表示不会抛出异常,反之可能抛出异常。不带常量的noexcept相当于noexcept(true)。noexcept可以有效地阻止异常的传播与扩散。

6、支持就地初始化。

class Init {
private: 
    int a = 1; 
    string name{“hello”}; 
};

      类的构造函数的初始化列表要先于就地初始化。

7、sizeof可作用的表达式包括类成员表达式。如:class Name{public: int a; }; sizeof(Name::a);

8、在c++11中,声明一个类为另一个类的友元时,不再需要使用class关键字。

9、final关键字的作用,使派生类不可覆盖它所修饰的虚函数。

10、虚函数描述符override。

11、支持函数模板的默认模板参数:template <typename T = int> void func(){}。

12、在c++11中,所谓委派构造,就是指委派函数将构造的任务委派给目标构造函数来完成这样一种类构造的方式。构造函数不能同时“委派”和使用初始化列表。如:

class Info {
public: 
	Info() { init(); } 
	Info(int i) : Info() { type = i; }
	Info(char e) : Info() { name = e; }	
private:
	void init();
	int type {1};
	char name{‘a’};
};
13、移动语义,移动构造函数。

class Example{
public:
	Example() : d( new int(3) ){}
	Example(const Example & eg) : d( new int(*(eg.d)) ){}
	Example(Example && eg) : d(eg.d){
		eg.d = nullptr;
	}
	~Example(){ delete d; }
private:
	int * d;
};
14、左值,右值与右值引用。
    可以取地址的、有名字的就是左值;反之不能取地址的、没有名字的就是右值。
    在c++11中,右值由两个概念构成:一个是将亡值,一个是纯右值。纯右值指用于辨识临时变量和一些不跟对象关联的值。而将亡值则是c++11新增的跟右值引用相关的表达式,这样的表达式通常是将要被移动的对象,如返回右值引用T&&的函数返回值、std::move的返回值等。剩余的可以标识函数、对象的值都属于左值。
    在c++11中,右值引用就是对一个右值进行引用的类型。事实上,由于右值通常不具有名字,我们也只能通过引用的方式找到它的存在。如:T && a = getValue(); 若getValue返回一个右值,a即为右值引用,其值等于getValue函数返回的临时变量的值。通常情况下,右值引用是不能绑定到任何的左值的。
    为了区别,我们称C++98的引用为“左值引用”。在C++98标准中,常量左值引用可以接受非常量左值、常量左值、右值对其进行初始化。而且在使用右值对其初始化的时候,常量左值引用还可以像右值引用一样将右值的生命期延长。不过相比于右值引用所引用的右值,常量左值所引用的右值在它的“余生”中只能是只读的。
    可以通过标准库<type_traits>提供的三个模板类:is_rvalue_reference、is_lvalue_reference、is_reference来判断引用类型。如:cout<<is_rvalue_reference<string &&>::value;

15、std::move
    在c++11中,标准库在<utility>中提供了一个有用的函数std::move,std::move(xxx)的作用是强制一个左值成为右值引用。从实现上来讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);
    在标准库中,我们还可以用一个std::move_if_noexcept的摸板函数替代move。该函数在类的移动构造函数没有noexcept关键字修饰时返回一个左值引用从而使变量可以使用拷贝语义,而在类的移动构造函数有noexcept关键字修饰时,返回一个右值引用,从而使变量可以使用移动语义。std::move_if_noexcept是以牺牲性能保证安全的一种做法。

16、完美转发
    所谓完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。如:
    template <typename T>
    void IamForwording(T t) { IrunCodeActually(t);  }
    IamForwording是一个转发函数模板。而函数IrunCodeActually则是真正执行代码的目标函数。对于IrunCodeActually而言,它总是希望转发函数将参数按照传入IamForwording时的类型传递,而不产生额外的开销,就好像转发者不存在一样。
    在C++11中,通过引入一条所谓“引用折叠”的新语言规则,并结合新的模板推导规则来完成完美转发。

    引用折叠总是优先将其折叠为左值引用。进一步的转发函数如下:
    template <typename T>
    void IamForwording(T && t) { IrunCodeActually(static_cast<T &&>(t)); }
这里的static_cast的作用类是于std::move,但是C++11中用于完美转发的函数不是move,而是forward。我们可以把转发函数改成这样:
    template <typename T>
    void IamForwording(T && t) { IrunCodeActually(forward(t)); }

17、explicit
    explicit的作用,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。在C++11中,标准将explicit的使用范围扩展到了自定义的类型转换操作符上,以支持所谓的“显式类型转换”。如:

class A {};
class B{
public:
        explicit operator A() const {return A();}
};
18、初始化列表
    在C++11中,可以对自定义类型,集合、列表等使用花括号进行快速初始化。这样一来,有以下几种初始化方式:
    a、等号“=”加上赋值表达式,如:int a = 3 + 4。
    b、等号“=”加上花括号的初始化列表,如:int a = {3 + 4};
    c、圆括号式的表达式列表,如:int a(3 + 4);
    d、花括号式的初始化列表,如:int a{3 + 4};
    自定义的类使用列表初始化。只要#include了<initializer_list>头文件,并且声明一个以initializer_list<T>模板类为参数的构造函数。如:

class A{
public:
	A(initializer_list< pair<int,int> > lt){
		auto i = lt.begin();
		for (; i != lt.end(); ++i)
			data.push_back(*i);
	}
private:
	vector< pair<int,int> > data;
};
    同理,函数的参数列表也可以使用初始化列表。
    在C++11中,使用初始化列表进行初始化的数据,编译器是会检查其是否发生类型收窄的。类型收窄指变量a从类型A转化为类型B再转化为类型A时,值发生了变化。如:int a = 2.6f;发生收窄,通过编译。 int a{2.6f};发生收窄,不能通过编译。

19、POD
    POD即Plain Old Data。表示是一个普通的类型,与C兼容。C++11将POD划分为两个基本概念的集合,即:平凡的(trivial)和标准布局的(standard layout)。
    平凡的定义:
    a、拥有平凡的默认构造函数和析构函数。或用=default修饰
    b、拥有平凡的拷贝构造函数和移动构造函数。活用=default修饰
    c、拥有平凡的拷贝赋值运算符和移动复制运算符。
    d、不能包含虚函数以及虚基类。
    可以用<type_traits>中的is_trivial<T>::value来判断是否是一个平凡的类型。
    标准布局的定义:
    a、所有非静态成员有相同的访问权限(public,private,protected)
    b、在类或结构体继承时,满足以下两种情况之一:
        b1、派生类有非静态成员,且只有一个仅包含静态成员的基类。
        b2、基类有非静态成员,而派生类没有非静态成员。
        非静态成员不能同时出现在基类和派生类中。多重继承中,一旦非静态成员出现在多个基类中,派生类也不属于标准布局。
    c、类中第一个非静态成员的类型与其基类类型不同。
        在C++标准中,如果基类没有成员,标准允许派生类的第一个成员与基类共享地址。表明基类没有占据任何实际空间。但如果派生类的第一个成员仍然为基类,编译器会为其分配空间,因为C++标准要求类型相同的对象必须地址不同。
    d、没有虚函数和虚基类。
    e、所有非静态数据成员均符合标准布局类型,其基类也符合标准布局。
    可以用<type_traits>中的is_standard_layout<T>::value来判断是否是一个标准布局的类型。
    同样地,可以用<type_traits>中的is_pod<T>::value来判断是否是一个POD。

20、用户自定义字面量操作符
    typeA operator”” _X(T t) {}。函数会解析以_X(自定义的)为后缀的字面量,返回一个typeA类型。如:

struct Watt{ unsigned int v; };
Watt operator “” _w(unsigned long long v){
	return {(unsigned int)v};
}
void main(){
	Watt capacity = 1024_w;
}
使用规则如下:
    a、如果字面量为整型数,那么字面量操作符只可接受unsigned long long或者const char *为其参数。当unsigned long long无法容纳该字面量时,编译器会自动将该字面量转化为以’\0’为结束符的字符串,并调用以const char*为参数的版本进行处理。
    b、如果字面量为浮点型数,则字面量操作符函数只可接受long double或者const char*为参数。
    c、如果字面量为字符串,则字面量操作符函数只可接受const char *,size_t为参数。
    e、如果字面量为字符,则字面量操作符函数只可接受一个char为参数。
    使用时应注意:
    a、operator””与用户自定义后缀之间必须有空格。
    b、后缀建议以下划线开始。
21、模板的别名
    在C++中,使用typedef为类型定义别名。如:typedef int myint;在C++11中,也可以使用using来定义别名,如:using myint = int。我们可以使用is_same<T a,T b>::value来判断a和b是否是同一个类型。在模板编程中,我们可以使用typedef不能达到的效果:
    template<typename T> using MapString = std::map<T, char *>;
    MapString<int> numberString;

22、右尖括号>的改进
    C++11标准要求编译器智能地去判断在哪些情况下>>不是右移符号。

23、auto类型推导
    C++11重定义了auto关键字来实现类型推导,auto声明变量的类型必须由编译器在编译时期推导而得,编译器在编译时期会将auto替代为变量实际的类型。
    auto不能用作函数形参、结构体中非静态成员变量等。
24、decltype
    decltype也能进行类型推导,但与auto使用方式不同,如:
    int i;
    decltype(i) j = 0;
    float a;
    double b;
    decltype(a + b) c;
    decltype总是以一个普通的表达式为参数,返回该表达式的类型。decltype可以将获得的类型来定义另外一个变量,它也是在编译时期推导。
    decltype(e)推导的四条规则:
    a、如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么decltype(e)就是e所命名的实体的类型。如果e是一个被重载的函数,则会导致编译时错误。
    b、否则,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&。
    c、否则,假设e的类型是T,如果e是一个左值,则decltype(e)为T&。
    e、否则,假设e的类型是T,则decltype(e)为T。
    与auto类型推导时不能“带走”cv限制符(即const,volatile)不同,decltype是能够“带走”表达式的cv限制符的。不过,如果对象的定义中有const或volatile限制符,使用decltype推导时,其成员不会继承const或volatile限制符。
    与auto相同的,decltype从表达式推导出类型后,进行类型定义时,也会允许一些冗余的符号。比如cv限制符,引用符号&等,通常情况下,如果推导出的类型已经有了这些属性,冗余的符号则会被忽略。需要注意的是,auto中,*也可以是冗余的,但decltype后的*,并不会被编译器忽略。如:
    int i = 1;
    int & j = i;
    int * p = &i;
    decltype(j) & v = i;    //冗余的&,被忽略
    decltype(p) * p1 = &i;    //无法通过编译

25、追踪返回类型
    使用auto和decltype来获取函数返回类型,如:

template<typename T1,typename T2>
auto sum(T1 & t1, T2 & t2) -> decltype(t1 + t2){
	return t1 + t2;
}
auto pf1() -> auto (*)() -> int (*)() { return nullptr; }

26、基于范围的for循环
    int arr[5] = {1,2,3,4,5};
    for (int & e : arr)
        e *= 2;
    也可以用auto替代:
    for (auto & e : arr)
        e *= 2;
    使用注意:for循环迭代的范围是可确定的。

27、强类型枚举
    以前的枚举类有这些缺点:非强类型作用域,允许隐式转换为整型,占用存储空间及符号性不确定等。C++11引入强类型枚举解决这些问题,声明强类型枚举非常简单,只需在enum后加上关键字class。如: enum class Type{General,Light,Medium};优点如下:
    a、强作用域,强类型枚举成员的名称不会被输出到其父作用域空间。
    b、转换限制,强类型枚举成员的值不可以与整型隐式地相互转换。
    c、可以指定底层类型。强类型枚举默认的底层类型为int,但也可以显示地指定底层类型,方法是在枚举名称后面加上“: type”,其中type可以是除wchar_t以外的任何整型。如:enum class Type : char {General,Light,Medium};
28、C++11的智能指针
    unique_ptr形如其名,与所指对象的内存绑定紧密,不能与其他unique_ptr类型的指针对象共享所指的内存,可以通过移动语义转移。从实现上讲,unique_ptr则是一个删除了拷贝构造函数,保留了移动构造函数的指针封装类型。
    shared_ptr形如其名,允许多个该智能指针共享地“拥有”同一堆分配对象的内存。与unique_ptr不同的是,由于在实现上采用了引用计数,所以一旦一个shared_ptr指针放弃了“所有权”,其他的shared_ptr对对象内存的引用并不会受到影响。只有引用计数归零的时候,shared_ptr才会真正释放所占用的堆内存的空间。
    weak_ptr,它可以指向shared_ptr指针指向的对象内存,却并不拥有该内存。使用weak_ptr的成员lock,则可以返回其指向内存的一个shared_ptr对象,且所指对象已经无效时,返回指针空值。

29、编译时期的常量修饰符constexpr
30、变长模板参数
31、快速退出:quick_exit和at_quick_exit

32、空指针nullptr
33、”= default”和”= delete”更精细的控制默认版本函数。
34、lambda
    lambda函数的语法定义如下:
    [capture](parameters) mutable ->return-type{statement}
    其中:
    [capture]:捕捉列表。捕捉列表总是出现在lambda函数的开头处。事实上,[]是lambda引出符。编译器根据该引用符判断接下来的代码是否是lambda函数。捕捉列表能够捕捉上下文中的变量以供lambda函数使用。
    (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号()一起省略。
    mutable:mutable修饰符。默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略。
    ->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。出于方便,不需要返回值的时候也可以连同符号->一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导。
    {statement}:函数体。内容与普通函数一样,不过除了可以使用参数外,还可以使用所捕获的变量。
    语法上,捕捉列表由多个捕捉项组成,并以逗号隔开。捕捉列表有如下几种形式:
        [var]表示值传递方式捕捉变量var。
        [=]表示值传递方式捕捉所有父作用域的变量(包括this)。
        [&var]表示引用传递捕捉变量var。
        [&]表示引用传递捕捉所有父作用域的变量(包括this)。
        [this]表示值传递方式捕捉当前的this指针。
    通过一些组合,捕捉列表可以表示更复杂的意思。如:
        [=, &a, &b]表示以引用传递的方式捕捉变量a和变量b,值传递方式捕捉其他所有变量。
        [&, a, this]表示以值传递方式捕捉变量a和this,引用传递方式捕捉其他所有变量。
    不过需要注意的是,捕捉列表不允许变量的重复传递。会导致编译时期错误。如:[=, a]、[&, &this]。
    lambda函数在C++11标准中默认是内联的。
    lambda函数及与其等价的仿函数:

    对于按值传递的捕捉列表,其传递的值在lambda函数定义的时候就已经决定了。而按引用传递的捕捉列表变量,其传递的值则等于lambda函数调用时的值。因此,在使用lambda函数的时候,如果需要捕捉的值成为lambda函数的常量,则通常用按值传递的方式。反之,如果需要捕捉的值成为lambda函数运行时的变量,则采用引用传递的方式。
    严格来讲,lambda函数并非函数指针。不过C++11标准却允许lambda表达是向函数指针的转换,但前提是lambda函数没有捕获任何变量,且函数指针所示的函数原型,必须跟lambda函数有着相同的调用方式。

35、C++11支持的4种新特性:对齐方式、通用属性、Unicode、以及原生字符串字面量。

转载出处:http://blog.csdn.net/sharing_li/article/details/50418864

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值