C++11

1.long long新类型

2.列表初始化

int t=0;

int t={0};

int t(0);

int t{0};

注意:如果我们使用列表初始化有丢失信息的风险,则编译器报错

long double ld=3.1415926536;

int a{ld},b={ld};//错误

int c(ld),d=ld;//正确,会丢失数据

3.空指针nullptr

int *p1=nullptr;

int *p2=0;

int *p3=NULL;//尽量避免

4.constexpr类型

const类型不一定是常量表达式,常量表达式指的是在编译的时候就知道值大小

如:

constint sz=str.size();

str的长度如果在编译的时候无法确定,则sz就不是常量表达式

而声明为constexpr的变量一定是个常量:

constexprint mf=20;//20是常量表达式

constexprint limit=mf+1;//mf+1是常量表达式

constexprint sz=size();//只有size()是一个constexpr函数时才能编译通过

            指针与constexpr

如果用constexpr声明了一个指针,则constexpr仅对指针有效(注意与const的区别)

constint *p=nullptr;//p是一个指向整型常量的指针

constexprint *q=nullptr;//q是一个指向整形的常量指针

如果要声明一个指向常量的常量指针,使用:

constexprconstint * q=&i;

5.类型别名

传统方法是使用typedef

typedefunsignedint UINT;

C++11规定一种新方法:

using UINT=unsignedint;

注意:指针、常量、类型别名

typedefchar *pstring;

const pstring cstr=0;//指向char的常来那个指针

const pstring *ps;//ps是一个指针,对象是一个指向char的常量指针

6.auto类型说明符

auto定义的类型必须要有初始值,因为编译器要分析实际类型

auto i=0;//iint

auto j=3.14;//jdouble

auto k;//错误

auto可以同时声明多个变量,但是同时声明的所有变量类型要相同

auto i=0,*p=&i;//正确

auto sz=0;pi=3.14;//错误

复合类型、常量和auto

引用:

int i=0,&r=i;

auto a=r;//a为整型

const,auto会忽略顶层const,底层const会保留

constint ci=i,&cr=ci;

auto b=ci;//b为整型ci顶层const特性被忽略

auto c=cr;//c为整型crci的别名

auto d=&i;//d是一个整型指针i不为常量

auto e=&ci;//e是一个指向整型常量的指针常量对象取地址是底层const

如果希望推断出的auto类型是顶层const,需要明确指出:

constauto f=ci;//ci的推演类型为int,而fconst int

将引用类型设为auto,原来的初始化规则仍然适用

auto &g=ci;//g是整型常量引用,绑定到ci

auto &h=42;//错误,不能为非常量引用绑定字面值(忽略顶层const

constauto &j=42;//正确常量引用绑定字面值

注意,声明多个变量时,*与&是声明符的一部分,而不是基本数据类型的一部分

auto k=ci,&l=i;//正确

auto &m=ci,*p=&ci;//正确

auto &n=i,*p2=&ci;//错误iint&ciconst int *

7.decltype类型指示符

decltype推断变量(函数)类型

decltype(f()) sum=x;//sum的类型就是f的返回值类型

注意,decltype与auto对const处理的区别:auto会忽略顶层const,而decltype会保留顶层const

constint ci=0,&cj=ci;

decltype(ci) x=0;//xconst int

decltype(cj) y=x;//yconst int&

decltype(cj) z;//错误zconst int&必须绑定值

引用一直是以其所指对象的同义词出现,但是对于decltype并非如此(会保留引用类型)

如果表达式的内容是解引用操作,decltype会得到引用类型

int i=42,*p=&i,&r=i;

decltype(r+0) b;//加法的结果是int,所以b是一个未初始化的int

decltype(*p) c;//错误cint&

注意:decltype((variable))(注意是双层括号)的结果是引用,而decltype(variable)的结果只有当variable本身是一个引用是才是引用

decltype((i)) d;//错误dint&需要绑定值

decltype(i) e;//正确e是一个未初始化的int

8.类内初始值

C++11规定,可以为类内数据成员提供一个初始值用于初始化,如果没有提供,将进行默认初始化

注意:不能使用圆括号,可以使用花括号或等号

9.使用auto或decltype缩短类型长度

同时可以避免无符号数与有符号数可能带来的问题

10.范围for

for(declaration:expression)

statement

如果想要用范围for改变对象中的值,需要把循环变量定义为引用

string s("hello world");

for(auto &c:s){

c=toupper(c);

}

cout<<s<<endl;

11.定义vector对象的vector

在C++11标准之前,如果要定义一个vector的vector,必须在两个>之间添加空格:

vector<vector<int> > arr;

而新标准不用这样操作:

vector<vector<int>> arr;//C++11合法

12.vector的列表初始化

注意区分圆括号与花括号

vector<

vector<int> v1{10};//一个元素,10

vector<int> v1(10,1);//10个元素,都为1

vector<int> v1{10,1};//两个元素,10,1

使用花括号时,初始化过程会尽可能把花括号内的值当成元素初始值的列表来处理,只有在无法执行列表初始化时才会考虑其他初始化方式。

vector<string> v5{"hi"};//列表初始化

vector<string> v6("hi");//错误

vector<string> v7{10};//转化为圆括号

vector<string> v7(10);//10个空字串

13.容器的cbegin与cend函数

cbegin和cend返回const迭代器,当不需要对元素进行修改时,最好使用const迭代器

14.标准库函数begin与end

在容器中,有两个同名函数,功能类似,但是标准库begin与end不是成员函数,它的参数为数组

int ia[]={1,2,3,4,5,6,7,8};

int *beg=begin(ia);

int *last=end(ia);

这两个函数定义在iterator中

15.使用auto和decltype简化声明

int ia[3][4];//大小为3的数组每个元素都是含有4个整数的数组

int (*p)[4]=ia;//p指向含有4个整数的数组

p=&ia[2];//p指向ia的尾元素

在上述声明中圆括号必须有

int *ip[4];//整型指针的数组

int (*p)[4];4个整数的数组的指针

可以用auto自动推断类型,避免出错

16.除法舍入规则

C++11规定整数除法一律向0取整(即切除小数部分)

17.初始值列表赋值

int k=0;

vector<int> vi;

k={5};//正确

k={3.14};//错误,窄化转换

vi={0,1,2,3,4};//正确

18.sizeof用于类成员

sizeof可用于类成员而不需要类的对象(想知道类成员大小并不需要真的获取类成员)

19.范围for 2

不能通过范围for添加或删除元素,因为范围for存储了end()的值,增加或删除会使迭代器失效

20.标准库initializer_list类

如果实参数量未知但是类型都相同,可以使用initializer_list类型形参

void error_msg(initializer_list<string> il){

for(auto p:il){

cout<<p<<endl;

}

}

error_msg({"hello","world"});

error_msg({"I","love","you"});

使用vector等也可以

21.列表初始化返回值

vector<string> func(){

return {"hello","world"};

}

22.尾置返回类型

int func(int a){

return0;

}

如果使用尾置返回类型则可以写作:

auto func(int a)->int{

return0;

}

对于返回值类型比较复杂的函数最有效,如:返回数组指针的函数

int (*func(int i))[10]{

//函数体

}

等价于

auto func(int i)->int(*)[10]{

//函数体

}

23.使用decltype简化返回类型定义

我们知道返回的类型指向哪个数组,就可以使用decltype关键字声明返回类型

int odd[]={1,3,5,7,9};

int even[]={0,2,4,6,8};

decltype(odd) *arrPtr(int i)}{

return (i%2)?&odd:&even;

}

注意:decltype并不负责吧数组转换为对应的指针,所以要在函数声明时加一个*

24.constexpr函数

constexpr函数是指能用于常量表达式的函数,函数的返回值以及所有的参数都必须是字面值类型,函数体中必须有且只有一条return语句

但是,C++11允许constexpr返回值并非一个常量

constexprint new_sz(){

return42;

}

constexpr size_t scale(size_t cnt){//如果cnt是常量则返回常量

return new_sz()*cnt;

}

int arr[scale(2)];//正确

int i=2;

int a2[scale(i)];//错误scale(i)不是常量表达式

注意:inline、constexpr可以在程序中多次定义,但是多次定义必须完全一致,所以内联函数和constexpr函数通常放在头文件中

25.使用=default生成默认构造函数

如果自定义了类的带参构造函数,则编译器不会生成默认构造函数,这时可以用=default生成默认构造函数

class A{

A(int t);

A()=default;//会生成默认构造函数

};

=default可以在类内部声明定义,也可以在类外部定义,如果在类内部,则默认构造函数是内联的,否则是非内联的(其他成员函数也是如此)

26.类内成员初始化

当我们提供一个类内初始化值时,必须使用等号或花括号表示(不能使用圆括号)

27.委托构造函数

委托构造函数是指把部分(或全部)职责委托给其他构造函数

class A{

A(int a);

A():A(0){};

};

28.constexpr构造函数

含有constexpr构造函数的类叫constexpr类,constexpr构造函数既要满足constexpr函数的要求又要满足构造函数的要求,,所以constexpr构造函数的函数体一般是空的

constexpr构造函数用于生成constexpr对象以及constexpr函数的参数或返回类型

29.用string对象作为文件名

在旧的C++标准中,文件名只能是C风格字符串

cosnt char * const fileName="a.txt";

ifstream fi(fileName);

string  fileName2="b.txt";

ifstream fi(fileName2.c_str());

在新的C++标准中,文件名既可以是string对象,也可以是C风格字符串

string  fileName3="c.txt";

ifstream fi(fileName3);//C++11中正确

30.array与forward_list

array与forward是C++新标准添加的内容,array替代内置数组,大小固定,但更安全,更易使用,forward替代手写链表,不支持size()

C++程序应该使用标准库容器而不是原始数据结构,如:内置数组

通常,使用vector是最好的选择,除非有更好的理由选择其他容器

31.容器的cbegin与cend

以前的C++标准中,const对象的begin()返回const类型的迭代器,否则返回普通iterator,如果要使用const迭代器,必须显示指定。由于新标准中添加了auto类型,所以同时添加了cbegin和cend,用于返回一个非const(const同样适用)对象的const迭代器

当不需要写访问时,尽量使用cbegin和cend

32.容器的列表初始化

容器用列表初始化时,除了array外,初始化列表隐含制定了容器大小

33.标准库swap

成员函数swap会交换内部数据结构,不会交换元素(array除外),除string外,指向容器的迭代器、引用和指针在swap操作后都不会失效

array对象swap时间与array对象的元素数量成正比

标准库swap在泛型编程中非常重要

统一使用非成员swap(标准库swap)是个好习惯

34.insert的返回值

insert操作后,会返回插入元素的迭代器

35.容器的emplace成员

emplace_back使用已有空间重新构造

push_back创建一个临时对象并且把它压入容器

36.shrink_to_fix

shrink_to_fix将capacity()减小为与size()相同的大小

37.string数值转换

标准库函数:

to_string(val);

stoi(s,p,b);

stol(s,p,b);

stoul(s,p,b);

stoll(s,p,b);

stoull(s,p,b);

stof(s,p,b);

stod(s,p);

stold(s,p);

val为要转换的数字,s为要转换的字符串,p为s中第一个非数值字符的下标,b是转换基数

38.lambda表达式

[捕获列表](参数列表)->返回值类型{函数体}

lambda表达式可以使用捕获列表中列出的局部变量

直接写变量名是值捕获,加上&后是引用捕获,类似函数参数传递,使用引用捕获时,必须确保lambda执行时变量是存在的

尽量保持捕获简单化,尽量避免指针捕获与引用捕获

捕获列表中如果是=或&表示根据代码推断要捕获哪些内容,其中=是值捕获,&是引用捕获

捕获有以下形式,=和&必须是列表中的第一个,表示隐式捕获的捕获类型

[]

[names]

[&names]

[&]

[=]

[&,name]

[=,&name]

可用mutable形成可变lambda,这样的lambda表达式即使是值捕获也可以改变变量的值

一个引用捕获的变量是否可以修改依赖于此引用指向的是一个const类型还是一个非const类型

39.lambda表达式必须使用尾置返回类型

如果lambda表达式中只有一个单体return或无返回语句,可以省略返回值类型,否则必须使用尾置返回类型

40.标准库bind函数

bind定义在<functional>中

bind可以看作一个通用的函数适配器

一般形式为:

auto newCallable=bind(callable,arg_list);

newCallable是一个新的可调用对象,arg_list是一个以逗号分隔的参数列表

当我们调用newCallable时,newCallable会调用callable,并传递给它arg_list参数

arg_list中的参数可能包含_n的名字,其中n为整数,这些参数是占位符,表示newCallable的参数,其中_1表示第一个参数,_2表示第二个参数,以此类推

占位符定义在placeholder命名空间中,而placeholders定义在std中,所以需要使用usingnamespace std::placeholders;

void func(string str1,int num1);

auto newFunc=bind(func,_1,5);

newFunc("hello");//等价于调用func("hello",5);

基于bind的特点,可以用它重排参数顺序

bind拷贝其参数,如果参数需要是引用类型,则需要ref或cref(也定义在<functional>中)

ostream &print(ostream &os,const string&s,char c){

return os<<s<<c;

}

for_each(words.begin(),words.end(),bind(print,ref(os),_1<' '));

41.关联容器的列表初始化

map<int,int> mp={

{1,3},

{2,4}

};

42.pair返回值

新标准中,可以使用列表对返回值进行初始化

pair<string,int> process(vector<string> &v){

if(!v.empty()){

return {v.back,v.back().size()};

}else{

return pair<string,int>();

}

}

43.pair的列表初始化

对map进行insert时,要记住类型是pair,构成pair最简单的办法就是参数列表中使用花括号初始化

map<string,int> mp;

mp.insert({"hello",5});

44.无序容器

新标准定义了4个无序容器:unordered_map,unordered_set,unordered_multimap,unordered_multiset

如果关键字类型固有就是无序的,或者性能测试发现问题可以用哈希技术解决,就可以使用无序容器

无序容器对关键字的要求:

可以使用任意内置类型,但不能使用自定义类型,不过可以通过通过函数来替代==运算符和哈希值计算函数。

hash<key_type>是标准库提供的hash值生成函数

unordered_set<Foo,,FooHash);//使用FooHash生成哈希值,Foo必须有==运算符

45.智能指针

新标准提供了两种智能指针:

shared_ptr:允许多个指针指向同一个对象

unique_ptr:“独占”所指对象

标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象

这三个类型都定义在<memory>头文件中

shared_ptr会自动释放管理的内存,但是有两种情况例外:

(1).没有销毁不用的shared_ptr对象,如将其作为返回值却没有使用

(2).将shared_ptr放在一个容器中,却没有释放容器中的资源

46.动态分配内存列表初始化

int *arr=newint[5]{1,2,3,4,5};

47.auto与动态分配

如果我们提供了一个用括号包围的初始化器,就可以使用auto,但是只有括号中仅有单一初始化对象时才可以使用auto

auto p1=newauto{5};

auto p2=newauto{5,6};//错误,无法推断类型

48.unique_ptr类

在同一时刻,只能有一个unique_ptr指向一个对象,当unique_ptr被销毁时,他所指的对象也被销毁了

unique_ptr不支持赋值

unique_ptr<string> p1(new string("hello world"));

unique_ptr<string> p2(p1);//错误,unique_ptr不支持拷贝

unique_ptr<string> p3;

p3=p1;//错误unique_ptr不支持赋值

不能拷贝的规则有一个例外,可以拷贝一个将要被销毁的unique_ptr(函数返回一个局部的unique_ptr)

unique_ptr<int> close(int p){

return unique_ptr<int>(newint(p));

}

49.weak_ptr类

weak_ptr指向一个shared_ptr管理的对象,但是不会为shared_ptr增加引用计数,所以weak_ptr可能指向一个一个已经被释放的内存区

由于weak_ptr指向的内存区可能已经被释放,所以要通过lock成员函数判断对象是否还存在

if(shared_ptr<int> np=wp.lock()){//如果np不为空条件成立

//if中,npp共享对象

}

50.不能用范围for处理动态数组中的元素

new分配的所谓的数组其实不是数组,而是一个指向一块内存区的指针,由于不是数组类型,所以不能对动态数组调用begin和end(标准库函数),这些函数使用维度来返回指向首元素和尾后元素的指针,出于相同原因,也不能用范围for处理(所谓的)动态数组中的元素

动态数组不是数组类型

51.动态数组的初始化

可以采用列表初始化

int *p=newint[10]{1,2,3,4,5,6,7,8,9,0};

52.auto不能用于动态数组

可以用空括号对数组中的元素进行值初始化,但是不能栽括号中给出初始化器,这意味着不能用auto分配数组(auto无法推断类型)

53.allocator::construct调用任意构造函数

allocator(定义在<memory>中)可以使内存分配和对象构造分开

int n=10;

allocator<string> alloc;//可以分配string对象的allocator对象

autoconst p=alloc.allocate(n);//分配n个未初始化的string

auto q=p;

alloc.construct(q++);// *q为空串

alloc.construct(q++,10,c);// *q"cccccccccc"

alloc.construct(q++,"hello");//*q"hello"

在分配内存后,必须使用construct构造对象

对象的销毁使用destroy(只能对已经构造了的对象使用destroy)

54.将=default用于拷贝控制成员

通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本

55.使用=delete阻止拷贝

在新标准下,我们可以通过将拷贝构造函数和拷贝赋值运算符定义为删除的函数来阻止拷贝。

删除的函数是这样一种函数:虽然我们声明了他们,但是不能以任何方式使用它们。

在函数参数列表后面加上=delete来指出我们希望它定义为删除的

struct NoCopy{

NoCopy()=default;//使用默认构造函数

NoCopy(const NoCopy&)=delete;//阻止拷贝

NoCopy &operator(const NoCopy&)=delete;//阻止赋值

~NoCopy();//默认析构函数

};

56.移动构造函数和std::move

move定义在<utility>中

直接调用std::move而不是move(因为move同时是模板函数,与标准库冲突)

用移动类对象代替拷贝类对象

57.右值引用

右值引用是指必须绑定到右值的引用,通过&&获取右值引用

右值引用有一个重要性质:只能绑定到一个将要销毁的对象

int i=42;

int &r=i;//正确

int &&s=i;//错误不能将右值引用绑定到左值上

int &t=i+5;//错误i+5为右值

int &&u=i+5;//正确

constint &v=i+5;//正确const引用可以绑定到右值上

变量是左值,所以不能将一个右值引用绑定在一个变量上,即使变量本身是右值引用也不行

58.标准库move函数

虽然不能将一个右值引用绑定在一个变量上,但是可以通过标准库move函数将左值转换为右值引用类型

int rr1=42;

int &&rr3=std::move(rr1);//正确

我们可以销毁一个移后源对象,也可以对它进行重新赋值,但不能使用一个移后源对象的值

59.移动构造和移动赋值

为了让我们自己的类支持移动和拷贝,我们需要为其定义移动构造函数和移动赋值运算符,移动构造后,移后源不再指向被移动资源,所以要保证对源的析构是安全的

class StrVec{

public:

StrVec(StrVec&&) noexcept;//移动构造函数,不应该抛出异常

//其他函数

};

StrVec::StrVec(StrVec&&s) noexcept:/*成员初始化器*/

{

/*构造函数体*/

}

60.移动构造函数通常应该是noexcept

两个相互关联的事实:

移动操作通常不抛出异常,但是抛出异常是允许的

标准库容器能对异常发生时其自身的行为提供保障

只有在确保移动操作是安全的,容器才会调用移动构造函数(及移动赋值运算符),否则就会调用拷贝构造函数

61.移动迭代器

一般来说,一个迭代器的解引用返回一个指向元素的左值。与其他迭代器不同,移动迭代器的解引用运算符生成一个右值引用。

通过make_move_iterator函数将一个普通迭代器转换为一个移动迭代器。此函数接受一个迭代器参数,返回一个移动迭代器

标准库不保证哪些算法适用于移动迭代器,哪些不适用,由于移动一个对象可能销毁源对象,因此你只有在确信算法在为一个元素赋值或将其传递给一个用户定义的函数后不再访问它时,才能将移动迭代器传递给算法

建议:不要随意使用移动操作

在类代码中小心地使用move,可以大幅提升性能,而如果随意在普通用户代码中使用移动操作,可能导致莫名其妙、难以查找的错误。

在移动构造函数和移动移动赋值运算符这些类实现代码之外的地方,只有当你确信需要进行移动操作且移动操作是安全的,才可以使用std::move

62.引用限定成员函数

string s1,s2;

s1+s2="hello";

这种右值使用方式令人惊讶,但是编译通过

我们希望在自己的类中阻止这种用法,我们希望强制左侧运算对象(即,this指向的对象)是一个左值

我们指出this的左值/右值属性与const相同:

class Foo{

public:

Foo &operator=(const Foo&)&;//只能向可修改的左值赋值

//其他

};

Foo &Foo::operator=(const Foo&rhs)&{

return *this;

}

引用限定符可以是&或&&,分别指出this可以指向一个左值或右值,类似const,引用限定符只能用于(非static)成员函数,并且必须同时出现在函数的声明和定义中

对于&限定的函数,只将它用于左值,对于&&限定的函数,只用于右值

一个函数可以同时用const和引用限定,在这种情况下,const限定符必须在引用限定符之前

如果一个成员函数有引用限定符,则具有相同参数列表的所有版本都必须有引用限定符

63.function类模板

function类型的对象存储可被调用对象,对于重载函数,应该存储函数指针(可以使用lambda表达式)

64.explicit类型转换运算符

int i=42;

cin<<i;//cin将被转换为bool,然后被提升为intint<<int合法!

为了防止这种异常情况发生,C++11引入了显示类型转换运算符

class SmallInt{

public:

explicitoperatorint() const {return val;}//编译器不会自动转换

//其他

};

SmallInt si=3;//正确

si+3;//错误,不会隐式转换

static_cast<int>(si)+3;//正确

该规定存在一个例外:表达式被用作条件时会将显式的类型转换自动应用于它,如:if,while,do,for,!,||,&&,? :等

向bool的类型转换通常在条件部分,所以operator bool一般定义成explicit的

65.虚函数的override指示符

派生类可以在它覆盖的函数前加virtual关键字,但不是非得这么做,C++11允许我们在函数后添加一个override关键字标明(形参后面,const后面,引用限定符后面)

override会让编译器检测是否覆盖了虚函数,没有将会报错,便于调试

66.使用final关键字阻止继承

当我们不希望某个类被继承时,可以用final关键字

class NoDerived final{/*  */};//不能作为基类

class Base{/* */};

class Last final:Base{/* */};//正确

class Bad:NoDerived{/* */};//错误

class Bad2:Last{/* */};//错误

67.虚函数override和final指示符

虚函数可以通过对override阻止覆盖

struct D2:B{

void f1(int)const final;//不允许被覆盖

};

struct D3:D2{

void f2();

void f1(int) const;//错误D2f1声明为final

};

68.派生类中删除的拷贝控制与基类的关系

基类删除的函数在派生类也是删除的(因为派生类无法调用基类相关函数)

69.继承的构造函数

派生类可以重用基类构造函数

class B:public A{

public:

using A:A;

//其他

};

或者

class B:public A{

public:

B(int a):A(){

//函数体

}

};

70.令模板自己类型的参数成为友元

template<typename Type> class Bar{

friend Type;//将访问权限授予用来实例化Bar的类型

//...

};

71.模板类型别名

新标准允许我们为类模板定义一个类型别名

template<typename T> using twin=pair<T,T>

twin<string> authors;//authors的类型是pair<string,string>

72.模板默认实参

我们可以提供默认模板实参

template<typename T,typename F=less<T>>

int compare(const T &v1,const T &v2,F f==F()){

if(f(v1,v2))return -1;

if(f(v2,v1))return1;

return0;

}

F表示可调用对象,定义了一个F类型f,并绑定到可调用对象上

73.模板显式实例化

模板在使用时才会被实例化,所以可能在编译单元中实例化相同的模板,这种开销在大系统中将变得很严重

对每个实例化声明,在程序的某个位置必须有显式的实例化定义

externtemplateclass Blob<string>;//实例化声明

templateint compare (constint&,constint&);//实例化定义

74.尾置返回类型

显式指定模板实参会给用户增加额外的负担,而不会带来好处。

template<typename It>

auto func(It beg,It end)->decltype(*beg){

//处理

return *beg;

}

func的返回类型与解引用beg参数的结果相同,解引用返回一个左值。如果用int序列调用,就返回int&

75.引用折叠规则

template<typename T> void f3(T&&);

f3(42);//实参是一个int类型的右值,模板参数Tint

int i=42;

f3(i);//为何能编译通过??

两个例外规则:

将左值传递给函数的右值引用参数,且此右值指向模板类型参数(如T&&)时,编译器推断模板类型参数为实参的左值引用类型。所以当我们调用f3(i)时,编译器推断T的类型为int&,而不是int(这意味着参数是int& &&),通常我们不能直接定义引用的引用,但是可以通过类型别名完成

引用的引用会发生折叠

对于一个给定的类型X:

X& &

X&& &

X& &&

将会被折叠为X&

X&& &&

将会被折叠为X&&

所以参数类型int& &&被折叠为int&,因此编译通过

76.使用static_cast将一个左值转为右值引用

虽然可以通过static_cast将左值强制转为右值引用,但是尽量使用std::move

77.标准库forward函数

forward函数可以保持原始参数类型

当用于一个指向模板参数类型的右值引用函数参数(T&&)时,forward会保持实参类型的所有细节

尽量使用std::forward,标准库冲突问题

78.可变参数模板

一个可变参数模板就是一个可以接受可变数目参数的函数模板或模板类,可变数目的参数被称为参数包

两种参数包:模板参数包、函数参数包

用一个省略号来指出一个参数包

template<typename T,typename... Args>

void foo(const T&,const Args& ... args);

79.sizeof...运算符

sizeof...运算符用于获取参数包中参数数目

template<typename ... Args>

void g(Args ... args){

cout<<sizeof...(Args)<<endl;//类型参数数目

cout<<sizeof...(args)<<endl;//函数参数数目

}

80.可变参数模板与转发

结合forward与参数包

work(std::forward<Args>(args)...);

通常模板函数的参数应该是右值引用(&&),根据引用折叠,我们可以传递任何形式的参数

81.标准库tuple模板

tuple类似pair,但是它能关联多个类型的对象,tuple的构造函数是explicit的,所以

tuple<,'h',"hello"};//错误,除非显式转换

tuple<int,int,char,string> tu{0,1,'h',"hello"};//正确,会被转换为圆括号

make_tuple函数可以生成一个tuple

tuple一般用于快速定义结构体数据类型和返回多个不同类型的值

82.新的bitset运算

all:所有位置1返回true

count:1的个数

size:bitset的大小

IO运算符:

bitset<> bits;

cin>>bits;//输入1601

cout<<"bits:"<<bits<<endl;//打印刚输入的内容

83.正则表达式库

RE库定义在<regex>中

具体使用参见:http://www.cplusplus.com/reference/regex/regex/

84.随机数库<random>

新C++标准定义了随机数引擎类default_random_engine

为了获取指定范围的随机数,可以用分布类型对象uniform_int_distribution(无符号整数),uniform_real_distribution(实数),bernoulli_distribution(布尔)

当我们说随机数发生器时,是指分布对象和引擎对象的组合

85.浮点数格式化

hexfloat强制浮点数使用16进制

defaultfloat恢复默认状态

86.noexcept异常说明

noexcept说明指定某个函数不会抛出异常

void recoup(int) noexcept;//不会抛出异常

void alloc(int);//可能抛出异常

noexcept的位置在const以及引用限定符后,在final、override、=0之前

void recoup(int) noexcept;

void recoup(int) throw();

等价

87.noexcept运算符

noexcept(recoup(i));//如果recoup不抛出异常为true否则为false

void f()noexcept(noexcept(g()));//fg的异常说明一致

函数指针及该指针所指的函数必须有一致的异常说明

88.内联命名空间

//Place.h

inlinenamespace Place{

//...

}

namespace Place2{

#include"Place.h"

}

Place2::直接可以访问Place中的数据

89.继承构造函数与多重继承

C++11允许从多个类继承构造函数,但是如果从多个基类继承了喜爱那个同的构造函数(形参列表相同),就会发生错误,解决办法是定义相同版本的构造函数

struct B1{

B1()=default;

B1(string);

};

struct B2{

B2()=default;

B2(string);

};

struct D:public B1,public B2{

using B1::B1;

using B2::b2;

D()=default;//必须定义

D(string);

};

析构从下往上进行

90.有作用域的枚举类型

C++包含两种枚举,限定作用域的和不限定作用域的

带有作用域的枚举:

enumclass color{red,yellow,green};

访问时:

color t=color::green;

不限定作用域的枚举可以自动转换为int,而限定作用于的不会自动转换

91.枚举类型的前置声明

C++11中,我们可以声明一个enum,enum的前置声明(无论是隐式还是显式)必须指定成员大小

enum intValues:unsigned long;//必须指定

enum class color;//默认int

限定作用域的可以使用默认的int大小,而非限定作用域的必须显式指定

92.标准库mem_fun类模板

mem_fn定义在<functional>中

mem_fn接受一个成员指针,生成一个可调用对象,这个对象可以通过对象调用,也可以通过指针调用

auto f=mem_fn(&string::empty);

f(*svec.begin());//传入对象

f(&svec[0]);//传入指针

93.类类型的union成员

C++11中,union可以包含类成员,但是,当我们将union的值改为类类型成员对应的值,必须调用构造函数,相反,如果我们将一个类类型成员改为其他值时,必须运行该类型的析构函数

如果一个union含有类类型成员,并且定义了默认构造函数和拷贝控制成员,编译器会为union合成对应版本并将其声明为删除的

如果一个类有union数据成员,union中又有删除的拷贝控制成员,则该类与之对应的拷贝控制操作也将是删除的

94.C++11对多线程的支持

C++11已经从语言层面支持多线程了,不再需要调用Win API或者linux的相关函数

具体参见:         http://www.cplusplus.com/reference/thread/thread/?kw=thread

http://www.cplusplus.com/reference/mutex/mutex/?kw=mutex

等资料

~完~

C++11学习笔记的更多相关文章

  1. C++11 学习笔记 std::function和bind绑定器

    C++11 学习笔记 std::function和bind绑定器 一.std::function C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法 ...

  2. linux0.11学习笔记(1)

    公布软件包包括内容: bootimage.Z - 具有美国键盘代码的压缩启动映像文件: rootimage.Z - 以1200kB 压缩的根文件系统映像文件: linux-0.11.tar.Z- 内核 ...

  3. C++11学习笔记(5) —— override and final (转)

    原文转自 http://blog.csdn.net/fire_lord/article/details/8540592 1.简介 C++为我们提供了继承和虚函数的重写特性. 在派生类中,重写虚函数不强 ...

  4. 802.11学习笔记1-WIFI参数含义

    研究下wifi参数的含义 #The word of "Default" must not be removed Default CountryRegion= CountryRegi ...

  5. Linux就该这么学11学习笔记

    参考链接:https://i.cnblogs.com/EditPosts.aspx?opt=1 文件传输协议 一般来讲,人们将计算机联网的首要目的就是获取资料,而文件传输是一种非常重要的获取资料的方式 ...

  6. 【DirectX 11学习笔记】世界矩阵的理解-运动合成

    最近在看龙书,写一下自己的学习理解,主要是物体运动的合成. 物体于局部坐标系内构建,每个物体拥有自己的局部坐标系以及相应的顶点矩阵A,并通过世界矩阵变换到唯一的世界坐标系. 物体在某时刻发生了位移和旋 ...

  7. linux0.11学习笔记(2)

    makefile文件: makefile 文件是make 实用简介.make 程序是用Makefile最后一次改变的数据文件和代码文件(last-modification time)确定哪些文件需要更 ...

  8. C++11学习笔记之三lamda表达式,std::function, std::bind

    //lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout ...

  9. C++11 学习笔记

    unique_ptr 可以实现如下功能: 1.为动态申请的内存提供异常安全 2.讲动态申请的内存所有权传递给某函数 3.从某个函数返回动态申请内存的所有权 4.在容器中保存指针 5.auto_ptr ...

随机推荐

  1. 实战使用Axure设计App,使用WebStorm开发(6) – 迈向后端

    系列文章 实战使用Axure设计App,使用WebStorm开发(1) – 用Axure描述需求  实战使用Axure设计App,使用WebStorm开发(2) – 创建 Ionic 项目   实战使 ...

  2. Sizeof的计算看内存分配

    本文记录了有关sizeof的一些计算,主要有下面的四种情况:(如有错误,敬请留言) 使用sizeof()计算普通变量所占用的内存空间 sizeof计算类对象所占用空间的大小-用到了字节对齐 sixeo ...

  3. Thrift架构~从图中理解thrift,它事实上是一种远程过程调用

    thrift为我们简化了tcp通讯,它可以使用我们方便的建立各种语言的服务端与客户端,并实现客户端对服务器的远程过程调用,简单的说就是服务器通过thrift架构对外开放一些接口,并自己实现这些接口,如 ...

  4. 知方可补不足~Sqlserver中的几把锁和.net中的事务级别

    回到目录 当数据表被事务锁定后,我们再进行select查询时,需要为with(锁选项)来查询信息,如果不加,select将会被阻塞,直到锁被释放,下面介绍几种SQL的锁选项 SQL的几把锁 NOLOC ...

  5. Fedora 24 install MySQL

    Background I have work with mysql on the fedora OS, but currently fedora have no support mysql inste ...

  6. C#学习系列-.NET体系结构

    .NET框架概述 .NET 框架为.NET应用程序运行提供虚拟机环境,为.NET应用程序提供编译.运行.内存管理.垃圾回收.安全等服务.   .NET框架组成部分 1.公共语言运行时(Common L ...

  7. js的基本语句和语法

    字符串赋值:把字符串用双引号或单引号引起来,在(js.php)中:二.类型转换;parseint():转整数.parsefloat转小数:强制转换三.运算符表达式1数序运算:加减乘除   %取余:2逻 ...

  8. javascript_basic_02之数据类型、分支结构

    1.弱类型:声明无需指定数据类型,由值决定,查看变量数据类型:typeof(变量): 2.隐式转换:任何数据类型与string类型相加,结果为string类型: 3.显式(强制)转换: ①toStri ...

  9. XML学习笔记4——XSD简单数据类型

    XSD提供了数据类型,并且支持自定义数据类型,但这一切都是建立在XSD内置数据类型和一套扩展内置数据类型的规则基础之上的,在这一篇笔记中,就来看看XSD中的数据类型. 1.XSD数据类型图 先看一下数 ...

  10. [WPF]有滑动效果的进度条

    先给各位看看效果,可能不太完美,不过效果还是可行的. 我觉得,可能直接放个GIF图片上去会更好. 我这个不是用图片,而是用DrawingBrush画出来的.接着重做ProgressBar控件的模板,把 ...