C++11 新特性整理
1.新类型
新增long long和unsigned long long以支持64位的整型
新增char16_t和char32_t以支持16位32位的字符表示
原始字符串
VC++ 2013现在支持原始字符串字面值了。注意:它并不支持统一码字符串字面值。一个原始字符串字面值允许你避免转义那些在HTML,XML和正则表达式里运用得得心应手的特殊字符。下面是一个示例用法:
auto s1 = R"(This is a "raw" string)";
现在,s1是一个指向常量字符串值为“This is a "raw" string”的指针。尽管不支持嵌套双引号,这与C#支持的@string文字是类似的。那么要在一个字符串字面值中嵌入R"(...)"会怎样。这种情况下,你可以使用以下语法:
auto s2 = R"QQ(Example: R"(This is my raw string)")QQ";
现在,s2包含 Example: R"(This is my raw string)"。 在这个例子中,我把QQ作为界定符。这个界定符可以是任何长度不超过16的字符串。原始字符串字面值也可以包含换行:
auto s3 = R"(<tr><td>data</td></tr>)";
最后,不论他们什么时候添加统一码字符串字面值的支持,你都可以将它们连接起来并构成原始统一码字符串字面值。
2.统一的初始化
内置变量
int x = {5};
double y {2.75};
short quar[5] {4,5,6,7,9};
int* ar = new int[4]{2,4,6,8};
类对象
Stump s1{3};
Stump s2{4,5.0};
缩窄:禁止将数值赋给无法存储它的数值变量,但允许转换为更宽的类型
char c1{1.5f}; // error
double c2{66666}; // error
std::initializer_list:可用在构造函数的参数,列表中元素必须同一类型,或可转换为同一个类型.
3.声明
auto:自动推导类型,必须显示初始化
auto maton = 112;
auto pt = maton; // auto 是int
double fm(double,int);
auto pf = fm; // auto 是函数指针
decltype:将变量的类型声明为表达指定的类型
decltype(x) y;
decltype(x*n) q;
decltype(&x) pd;
应用于模板的例子:
template<typename T,typename U>
void ef(T t,U u){
decltype(T*U) tu;
...
}
返回类型后置:指定返回类型
double f1(double,int);
auto f2(double,int)->double; // 指定返回double
应用于模板的例子:
template<typename T,typename U>
void eff(T t,U u)->decltype(T*U){
...
}
模板别名:using =
typedef std::vector<std::string>::iterator itType; // 旧版本
using itType = std::vector<std::string>::iterator; // 新版本
新版本的模板别名可以用在模板部分具体化
template<typename T>
using arr12 = std::array<T,12>;可替换为
arr12<double> a1;
arr12<std::string> a2;
nullptr:空指针
消除了以前版本用NULL和0带来的问题.以前用0即可表示指针常量,又可以表示整数常量。
4.智能指针
C++抛弃了auto_ptr,
并新增了三种智能指针:uique_ptr,shared_ptr,weak_ptr
所有新增的智能指针能够与STL容器和语义协同工作!
5.异常规范方面的修改
以前:
void f501(int) throw(bad_dog); // 捕捉类型bad_dog可能引发的异常
新增:
void f875(short,short) noexcept; // 指示编译器此函数不会引发异常
6.作用域内枚举
旧版枚举有以下问题:
1.类型检查低级;
2.同一个类中如有两个枚举,其枚举成员不能同名;
3.枚举作用域为枚举定义所属的作用域
4.移植性差
新版本
enum class New1{never,sometimes};
enum struct New2{newver,lever,server};
使用是必须显示限定:New1::never
7.对类的修改
explicit:禁止单参数构造函数导致的自动转换符
类内成员初始化
class Test1
{
public:
Test1(int n)
{
num=n;
}//普通构造函数
private:
int num;
};
class Test2
{
public:
explicit Test2(int n)
{
num=n;
}//explicit(显式)构造函数
private:
int num;
};
int main()
{
Test1 t1=12;//隐式调用其构造函数,成功
Test2 t2=12;//编译错误,不能隐式调用其构造函数
Test2 t2(12);//显式调用成功
return 0;
}
8.模板和STL方面修改
(1)for循环
int arr[5]{1,2,3,4,5};
for(int x:arr){
}
(2)新的STL容器
forward_list 单向链表
unordered_map
unordered_multimap
unordered_set
unordered_multiset
(3)新的STL方法
cbegin(),cend(),crbegin(),crend(),这些新方法将元素视为const
(4)export关键字的功能被停用,但关键字还保留
(5)valarray升级:用于基于范围的STL算法,新增begin()和end()方法,它们接收一个valarray对象参数
(6)尖括号:为了于运算符>>混乱,新标准要求在声明嵌套模版时使用空格将艰苦尖括号分开
std::vector<std::list<int>空格> v1;
9.右值引用
1.左值可以归纳为:左值表示程序中必须有一个特定的名字引用到这个值。
2.右值引用的是地址里的内容,所以相反右值可以归纳为:右值表示程序中没有一个特定的名字引用到这个值除了用地
址,例如:x+y所产生的数据使用&&表示,右值引用可关联到右值,即可出现在赋值表达式右边,但不能对其应用地址
运算符的值。
例子:
int x =10;
int y = 23;
int && r1 = 14;
int && r2 = 31;
double && r3 = std::sqrt(2.0);
10.移动语句
举例说明:
例子:在旧版本中复制大量对象到新地址后,再删除的过程
内存分析:先复制这些内存信息到新的地址,然后再删除原来的地址中的内存信息.
新增功能:把原来内存信息保留,将删除与之关联的变量记录
以上的新增功能称为移动语义,他避免了移动原始数据,只是修改了记录.
移动语句是通过右值引用来达成的!
class AA{
public:
AA(AA&& a1){}; // 移动构造函数
}
11.赋值
移动语义也适用于赋值运算符.即重载赋值运算符,然后参数为T&&
12.强制移动
让左值强制变成右值使用.
1.#include<utility>
2.使用std::move(左值)
13.特殊的构造函数
1.如果类没有提供复制构造函数,编译器将提供一个默认的.
2.如果类没有提供移动结构函数,编译器将提供一个默认的.
3.如果类提供了复制构造函数,析构函数,复制赋值运算符,编译器将不会自动提供移动构造函数和移动赋值运算符.
4.如果类提供了移动构造函数或移动赋值运算符,编译器将不会提供复制构造函数和复制赋值运算符.
14.默认的方法和禁用的方法
使用关键字default显式第声明这些方法的默认版本,即告诉编译器为函数生成默认实现
class AA{
AA()=default; // 默认方法
AA(AA&&){}
AA(const AA&)
}
使用关键字delete来用于使编译器禁止使用特定的方法.
class AA{
AA(double)=delete; // 禁用方法
AA(int){}
}
default只能用于6个特殊成员函数.
delete用于任何成员函数.
15.委托构造函数
允许你在一个构造函数的定义中使用另一个构造函数.
这样构造函数暂时将创建对象的工作委托给另一构造函数.
class AA{
AA();
AA(int);
AA(int,double);
};
AA(int kk):AA(kk,0.01){} // AA(int) 委托给 AA(int,double)
16.继承函数
class C1{
public:
int fn(int j);
double fn(double w);
void fn(double char* s);
};
class C2{
public:
using C1::fn; // 继承C1的fn
double fn(double dd){return dd;};
};
C2 c2;
int k = c2.fn(3); // 继承C1的fn
double z = c2.fn(2.4);
这种方法用于构造函数,可让派生类继承基类的所有构造函数.(包括复制构造函数,移动构造函数...)
17.Lambda函数
一种定义和应用函数的数学系统,这个系统让你用匿名函数。
普通函数:bool f3(int x){return x%3 == 0;}
lambda:[](int x){return x%3 == 0;}
分析:[]代替了函数名,返回值相当使用了decltyp进行推导
用途:通过使用lambda来替换函数指针或函数符构造函数!
例如:[](double x)->double{int y=x;return x-y;}相当于
double dd(double x){
int y=x;
return x-y;
}
lambda的优点:
1.距离:在函数调用时直观的给出定义,省的去跳转到函数体
2.简洁:语句简明
auto mod3 = [](int x){return x%3 == 0;}
count1 = std::count_if(n1.begin(),n1.end(),mod3);
3.效率:函数符和lambda不会阻止内联
4.功能:可访问作用域内任何动态变量
[z] 按值访问,z是变量的名称
[&count] 按引用访问,count是变量的名称
[&] 按引用访问所有动态变量
[=] 按值访问所有动态变量
[z,&count] 混合用法
18.包装器
这些包装器对象用于给其他编程接口提供更一致更合适的接口.
bind:可以让接收几个参数的函数与STL算法匹配
mem_fn:让成员函数作为常规函数进行传递
reference_wrapper:创建行为像引用但可被复制的对象
function:以统一的方式处理多种类似于函数的形式
19.可变参数模板
让你能够创建可变数量的参数的模板函数和模板类.
template<typename... Args>
void show_list(Args... args){
}
show_list(5,'L',0.5);
其他功能
并行编程
...