很久都没进来了,感觉最近很疲惫,今天我i什么要学这个东西呢,是因为自己被不同的人问了很多次,好歹自己也学过c++;被人问过却不知道c++11真的觉得很丢人,所以我这个菜鸟打算了解一下(虽然只是皮毛),这也是分内之事喽,一起学习学习,看看人家的介绍,自己想动手试一试(你也可以动动爪爪,哈哈),在看一本书叫《深入理解c++11》,大家可以瞅瞅
一:c++11的诞生
2011年11月,c++11/c++0x标准被标准委员会批准通过,至此c++11标准尘埃落定。发展史就简单介绍啦,本人觉得如果c++98/03如果比作一辆奔驰宝马汽车的话,那么C++11就是兰博基尼或者法拉利(哈哈),因为它不仅兼容c++03/98,而且在此基础上做了大量缺点的改进,还有许多新功能的增加,各种配置都该是最佳的,尽管未来还会不会有更ai的c++语言,就目前而言,还是很特点鲜明的吧。
整体的设计目标:
//使c++成为更好的适用于系统开发及库开发的语言(感觉c++的地位好像不如从前了)
//使得c++成为更容易教学的语言(语法更加一致化和简单化)
//保证语言的稳定性,以及c++03及c语言的兼容性
二:c++11的一些新特性
<1>c++11引入的新的关键字:
alignas
alignof decltype
auto(重新定义)
static_assert
using(重新定义)
noexcept
nullptr
constexpr
thread_local
<2>倾向于使用语言来实现特性库而不是扩展
<3>更倾向于通用的而不是特殊的手段来实现特性
eg :c++98中类型转化操作符可以参与隐式转化,而有时我们只是希望在显式时再发生转化
<4>不再是专家才能操纵的语言(菜鸟也可以)
eg:c++11采用最长匹配的解析规则
这是我用vs2012写的
这是我用dev写的(比较老,当时傻的还不知道为什么不对)
但是如果这样写就是对的:
<5>增强类型的安全性
c++11标准引入了“强类型枚举”;在c++98/03枚举会退化成整形,会与其他的枚举类型混淆,C++11则有修正
dev下:
dev也不行,vs2012支持c++11,肯定也不行
<6>与硬件紧密合作
c++11引入原子型,保证线程正确同步,为开发者和系统建立一个高效的同步机制
三:c++11的兼容性和稳定性
<1>保持与c++99兼容
1:_func_ 预定义标识符(vs里面我查了一下叫FUNCTION,我也不是很清楚啦哈哈)
2:pragma 操作符
保证头文件不被重复包含
#pragma once 等同于
#ifndef _x_H
#define _x_H
3:静态断言:
这就保证了指针不为null且数组的为有效数组了
c++11引入了static_assert:,使得错误更加容易找到,原因是assert是运行时的断言,而static_assert是编译时期的断言
传入两个参数,一个参数传入的是你要断言的表达式(常量Bool值),一个传入的警告信息(一个字符串)
这样就很容易知道错误在哪里了。。。。
4:long long 类型(至少64位)
5:快速初始化类成员变量
我们可以看出在dev里面写的,发现成员c可以就地初始,在vs里面却不行好奇怪,不知道为什么,不过可以肯定的是c++11是支持成员变量可以不通过初始化列表初始化成员变量,可以就地初始化
而且c++11还支持花括号赋初始值;类似于这样: struct Init{ int a = 0;double b {5.5}; };//就不做演示了。
6:外部模板
外部模板是c++11中关于模板性能上的一个改进。
我们在test.h的文件中声明了这样一个模板函数:tempate <typename T> void fun(T){}
在第一个test1.cpp文件中,我们定义了这样一行代码:
#include "test.h"
void test(){fun(3);}
在另一个test2.cpp文件中,我们也定义了这样一些代码
#include "test.h"
void test(){fun(3);}
由于两个源代码使用的模板函数参数类型一致,所以在编译test1.cpp的时候,编译器实例化出了fun<int>(int),而当编译test2.cpp的时候,编译器又在一次实例化出了函数fun<int>(int),这样,在test1.o和test2.o目标文件中,会有两份一摸一样的函数fun<int>(int),代码重复,在链接的时候,连接器通过一些编译器辅助的手段将重复的模板函数代码fun<int>(int)删除掉,只保留单一个副本,这样一来,就解决了模板实例化时产生的代码冗余问题,但是,如果这样的相同代码多了,会极大的增加编译器的便宜时间和链接时间,怎样解决呢,哈哈,当然就是c++11新引入的外部模板喽外部模板的使用依赖于显示实例化:类似于这样::
template<typename T> void fun(T){}
我们只需要这样声明一下:template void fun<int>(int);这就可以使得编译器在本编译器单元中实例化出一个fun<int>(int)版本的函数(强制实例化),而在c++11中,又加了外部模板的声明,外部模板的声明根显示的实例化差不多,加了一个关键字extern,大家应该并不陌生,对于上面的例子,我们可以这样做:extern template void fun<int>(int);
///
所以,对于上面的例子,我们可以这样修改:
我们首先在test1.cpp做显示的实例化:
#include "test.h"
template void fun<int>(int);//显示实例化
void test1(){fun(3);}
然后我们在test2.cpp中做外部模板的声明
#include "test.h"
template void fun<int>(int);//显示实例化
void test2(){fun(3);}
这样的话,在test2.o中不会再生成fun<int>(int)的实例化代码,因此在链接的时候,应该要比较轻松了吧。但是外部模板不能用于静态函数(local)
三:通用才是硬道理
1:右值引用:移动语句和完美转发
移动语句:对于我的理解就是将资源从一个对象拷贝到另一个对象的时候,不需要临时对象的创建,拷贝及销毁,能够大幅度提高c++程序的功能,它是将这些资源从一个对象转移到另一个对象。在别的资料看到这样一段话,感觉很形象,他说类比文件的剪切和拷贝,当我们将文件从一个目录拷贝到另一个目录时,速度要比剪切慢很多。
在c++中,我们可以定义移动拷贝构造函数和移动赋值函数
一般而言,当我们用临时对象拷贝构造新对象的时候,会在函数返回的时候产生临时对象,作为函数的返回值,而这个临时量会构造主函数的新对象,这样一来,调用两次构造函数,而c++11的做法是在临时对象构造a的时候不分配内存,让新对象的成员变量指向临时对象的堆内存资源,同时保证临时对象不释放所指向的堆内存,在构造完成后,临时对象被析构,新对象就偷走了临时对象所拥有的堆内存资源。(不过我们老师教的是直接调用构造函数,不产生临时量,谁能给我解释下,我还试了一下)
意思是将临时对象直接初始化了新对象的d,在放入新对象的内存中,不在调用拷贝构造函数。。。。。。
移动构造函数接收右值引用参数
左值引用接收左值,右值引用接收右值
int x = 0;
int &a = x;//左值引用
int &&a = 10;//右值引用
#include <utility>
std::move()函数强制一个左值成为右值,等同于一个类型转换:
static_cast<T&&>(lvalue)
这个比较经典,没有资源的申请释放,只是在移动资源。
完美转发,感觉其实就是对函数的一种包装,看起来比较统一整齐规范化,大家可以看看这个例子(自己也可以动动手,哈哈)
脑子好疼,就先写到这里,呼,后续在学习吧,哈哈,眼睛快睁不开了---------