一、C++11语言新特性
1.微小但重要的语法提升
void f(int);
void f(void *);
f(0);//call f(int)
f(NULL);//call f(int) if NULL is 0
f(nullptr);//call f(void *)
(1)nullptr是个新关键字。它被自动准换成各种pointer类型,但不会被准换成任何整数类型。
(2)nullptr的类型是nullptr_t,定义于
(3)nullptr_t是一个基础类型
2.以auto完成自动类型推导
(1)以auto声明的变量,其类型是会根据其初始值被自动推导出来,因此一定需要一个初始化操作:
auto i;//ERROR:can't deduce the type of i
3.一致性初始化与初值列
(1)初始化可因为小括号、大括号或赋值操作符的出现而发生
(2)C++11引入了“一致性初始化”概念,即面对任何初始化动作,可以使用相同语法。也就是使用大括号:
int values[]{1,2,3};
std::vector<int>v{2,3,5,7,11,13,17};
std::vector<std::string>cities{
"Berlin","New York","London","Braunschweig","BeiJing"
};
std::complex<double>c{4.0,3.0};
(3)初值列会强迫造成所谓的value initialization。意思是:即使某个local变量属于某种基础类型(通常会有不明确的值)也会初始化为0
int i;//i的值未定义
int j{};//j被初始化为0
int *p;//值未定义
int *P{};//p被初始化为nullptr
(4)窄化:精度降低或造成数值变动。对大括号是不成立的
int x1(5.3);//ok,x1 = 5
int x2 = 5.3;//ok,x2 = 5;
int x3{5.0};//错误,窄化
int x4 = {5.3};//错误,窄化
char c1{7};//ok
char c2{99999};//error:窄化:99999不是一个char型
std::vector<int>v1{1,2,4,5};//ok
std::vector<int>v2{1,2.3,4,5.6};//error:窄化
1)判定是否窄化转换是,依赖初值设定的实际值而非只是依赖类型
2)浮点数转化至整数永远是一种窄化
4.Rang-Based for
(1)为了避免调用每个元素的copy和析构函数,通常应该声明当前元素为一个从const reference。
(2)基本语法
for(decl:coll)
{
statement
}
当元素在for循环中被初始化为decl,不得有任何显示类型转换
class C
{
public:
explicit C(const std::string& s);
};
std::vector<std::string>vs;
for(const C &elem:vs)//ERROR
{
std::cout<<elem<<std::endl;
}
5.Move语义和Rvalue Reference
(1)c++11的一个最重要的的特性就是,支持搬迁语句。用以避免非必要拷贝和临时对象
6.关键字noexceptiom
用来指明某个函数无法或者不打算 抛出异常
(1)运行期检验:C++异常明细乃是被检验于运行期而非编译器,所以它无法对程序员保证每个异常都被处理。
(2)运行期开销:运行期检验会令编译器产出额外代码且妨碍优化。
(3)无法用于泛型码中:
7.关键字constexpr
用于让表达式核定于编译器
constexpr int square(int x)
{
return x*x;
}
8.带别名的模板
template<typename T>
using Vec = std::vector<T,MyAlloc<T>>;
Vec coll;
等价于std::vector<int,MyAlloc>coll;
10.Lambda
(1)lambda不可以是template,必须知名所有类型
(2)用于访问外部作用域的方法
1)[=]外部作用域以值传递方式传递给Lambda
可以读取所有可以读取的数据但不能改动他们
2)[&]以引用方式传递给Lambda
对所有可以涂改进行涂写动作都合法。
(3)为了获得passing by value和passing by reference 混合体,可以声明Lambda为mutable
auto f = [id]()mutable{
std::cout<<"id: "<<std::endl;
++id;
}
二、虽旧犹新的语言特性
(1)Member template 的一个特殊形式是template构造函数。这种东西通常被提供用于“对象被复制时给予隐式类型转换”的能力。
注意:template构造函数并不压制copy构造函数的隐式声明。如果完全吻合,隐式的copy构造函数会被生成出来,并被调用。
template<typename T>
class Myclass{
public:
template<typename U>
MyClass(const MyClass<U>& );
};
void f()
{
MyClass<double>xd;
MyClass<double>xd2(xd);
MyClass<int>xi(xd);
}
1.基础类型的明确初始化
(1)如果使用“一个明确的构造函数调用,但不给实参”,这样的语法,基础类型会被设定初始值为0
int i1;//未定义的值
int i2 = int();//被初始化为0
int i3{};//被初始化为0
2.main()定义式
(1)唯一“正确且具有移植性”的main()。
根据c++标准,main()只有两种定义式具备可移植性
int main()
{
...
}
和
int main(int argc,char * argv[])
{
...//argv,命令行实参形成的array
}
(2)可以(但非必要)以一个return语句终结main()
这意味着,任何程序离开main()时可以不写return语句。0以外的任何值都代表某种失败。