c++11知识点1_基础

1.概述
1.1.背景
C++11(草案原名C++0x)于 2011年9月1日出版发布C++11标准,正式名称为:
ISO/IEC 14882:2011 - Information technology -- Programming languages -- C++
取代1998年发布的C++标准第一版(C++98标准,全称ISO/IEC 14882:1998)和2003年发布的C++标准
第二版(C++03标准,全称ISO/IEC 14882:2003)。


1.2.改进之处
核心语言的领域被大幅改善,包括多线程支持、 泛型编程、统一的初始化,以及表现的加强。


(1)右值引用和转移语义
在旧标准C++语言中,临时量(术语为右值,因其出现在赋值表达式的右边)可以做参数传给函数,但只能被
接受为const &类型。这样函数便无法区分传给const &的是真正的右值还是普通const变量。而且,由于
类型为const &,函数也无法改变所传对象的值。


C++0x将增加一种名为右值引用的新的引用类型,记作typename &&。这种类型可以被接受为非const值,
从而允许改变其值。这种改变将允许某些对象创建转移语义。


比如,一个std::vector,就其内部实现而言,是一个C式数组的封装。如果需要创建vector临时量或者从
函数中返回vector,那就只能通过创建一个新的vector并拷贝所有存于右值中的数据来存储数据。之后这
个临时的vector则会被销毁,同时删除其包含的数据。


有了右值引用,一个参数为指向某个vector的右值引用的std::vector的转移构造器就能够简单地将该右值
中C式数组的指针复制到新的vector,然后将该右值清空。这里没有数组拷贝,并且销毁被清空的右值也不会
销毁保存数据的内存。返回vector的函数现在只需要返回一个std::vector<>&&。如果vector没有转移构
造器,那么结果会像以前一样:用std::vector<> &参数调用它的拷贝构造器。如果vector确实具有转移
构造器,那么转移构造器就会被调用,从而避免大量的内存分配。


考虑到安全因素,具名变量即使被声明为右值类型也不会被当作右值。如需把它当作右值,须使用库函数std::move()。


bool is_r_value(int &&)
{
return true;
}
bool is_r_value(const int &)
{
return false;
}
void test(int &&i)
{
is_r_value(i); // false
is_r_value(std::move(i)); // true
}


(2)泛化的常数表示式
C++语言一直具有常量表达式的概念。这些诸如3+4之类的表达式总是产生相同的结果且不具备副作用。
常量表达式给编译器带来了优化的可能,而编译器也经常在编译期执行此类表达式并将结果存放在程序中。
此外,C++语言规范中有一些地方需要使用常量表达式。定义数组需要常量表达式,而枚举值也必须是常量表达式。
然而,每当碰到函数调用或对象构造,常量表达式便不再有效。所以简单如下例便不合法:
int GetFive()
{
return 5;
}
int some_value[GetFive() + 5]; //创建一个包含10个整型变量的数组,在标准C++中不合法


这段代码在C++中不合法,因为GetFive() + 5不是一个常量表达式。
编译器无从知晓GetFive在运行期是否产生常量。
理论上,这个函数可能会影响某个全局变量,或者调用其他运行期产生非常量的函数。
C++0x将引入constexpr关键字,此关键字将使用户能保证某个函数或构造器在编译期产生常量。
上例可被改写如下:
constexpr int GetFive()
{
return 5;
}
int some_value[GetFive() + 5]; //在标准C++0x中合法
这段代码将使编译器理解并确认GetFive是个编译期常量。


在函数上使用constexpr将对函数功能施加严格的限制。
首先,函数必须返回非void类型。
其次,函数体必须具有"return /expr/"的形式。
第三,expr在参数替换后必须是常量表达式。该常量表达式只能调用其他定义为constexpr的函数,只能
使用其他常量表达式数据变量。
第四,常量表达式中一切形式的递归均被禁止。最后,这种带constexpr的函数在编译单元中必须先定义后调用。


变量也可被定义为常量表达式值。
constexpr double forceOfGravity = 9.8;
constexpr double moonGravity = forceOfGravity / 6;
常量表达式数据变量隐含为常量。它们只能存放常量表达式或常量表达式构造器的结果。


为了从用户自定义类型中构建常量表达式数据值,构造器在声明时可带constexpr。
同常量表达式函数一样,在编译单元中常量表达式构造器也必须先定义后使用。
常量表达式构造器函数体必须为空,而且它必须用常量表达式构造其成员。这种类型的析构器必须是平凡的。


由常量表达式拷贝构造的类型也必须被定义为constexpr,以使它们能从常量表达式函数中作为值被返回。
类的任何成员函数,包括拷贝构造器和操作符重载,都能被声明为constexpr,只要它们符合常量表达式函数的定义。
这就允许编译器在编译期不仅能拷贝类对象,也能对其实施其他操作。


常量表达式函数或构造器可以用非constexpr参数来调用。就如同一个constexpr整数常量可以被赋给一个
非constexpr变量一样,constexpr函数也可用非constexpr参数来调用,并且其结果也可存放在非constexpr
变量中。此关键字只是提供了在一个表达式的全部成员均为constexpr时其结果为编译期常量的可能性。


(3)对POD定义的修正
POD,Plain Old Data,指POD用来表明C++中与C相兼容的数据类型,可以按照C的方式来处理(运算、拷贝等)。


C++0x将放松某些关于POD的限制规则。
如果一个类或结构是平凡的,具有标准布局的,且不包含任何非POD的非静态成员,那么它就被认定是POD。
平凡的类或结构定义如下:
<1>.具有一个平凡的缺省构造器。(可以使用缺省构造器语法,如 SomeConstructor() = default;)
<2>.具有一个平凡的拷贝构造器。(可以使用缺省构造器语法)
<3>.具有一个平凡的拷贝赋值运算符。(可以使用缺省语法)
<4>.具有一个非虚且平凡的析构器。


一个具有标准布局的类或结构被定义如下:
<1>.所有非静态数据成员均为标准布局类型。
<2>.所有非静态成员的访问权限(public, private, protected) 均相同。
<3>.没有虚函数。
<4>.没有虚基类。
<5>.所有基类均为标准布局类型。
<6>.没有任何基类的类型与类中第一个非静态成员相同。
<7>.要么全部基类都没有非静态数据成员,要么最下层的子类没有非静态数据成员且最多只有一个基类有非静态数据成员。
总之继承树中最多只能有一个类有非静态数据成员。所有非静态数据成员必须都是标准布局类型。


(4)外部模板
在标准C++语言中,如果在某一个编译单元中编译器碰到一个参数完全指定的模板,它就必须实例化该模板。
这种做法可能大大延长编译时间,尤其在许多编译单元使用同样的参数实例化该模板时。
为了解决此问题,C++0x引入外部模板的概念。


C++已经拥有了迫使编译器在某一地点实例化模板的语法:
template class std::vector<MyClass>;
C++所缺乏的是防止编译器具现化某个模板的能力。
C++0x只是简单地将语法扩展为:
extern template class std::vector<MyClass>;
这段代码将告诉编译器不要在这个编译单元实例化此模板。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值