C++11入门
C++11入门
1. C++11简介
在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为 C++11之前的最新C++标准名称。不过由于TC1主要是对C++98标准中的漏洞进行修复,语言的核心部分则没 有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑, 第二个真正意义上的标准珊珊来迟。相比于* C++98/03***,C++11则带来了数量可观的变化,其中包含了约140 个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语 言 。相比较而言, C++11**能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅 功能更强大,而且能提升程序员的开发效率。
2. 列表初始化
C++98中{}的初始化问题
在C++98中,标准允许使用花括号{}对数组元素进行统一的列表初始值设定。比如:
int array1[] = {1,2,3,4,5}; int array2[5] = {0};
对于一些自定义的类型,却无法使用这样的初始化。比如:
vector<int> v{1,2,3,4,5};
就无法通过编译,导致每次定义vector时,都需要先把vector定义出来,然后使用循环对其赋初始值,非常不方便。
- C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加.
- 多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数即可。
- 注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin() 、 end()迭代器 以及获取区间中元素个数的方法size() .
#include <initializer_list> template<class T> class Vector { public: // ... Vector(initializer_list<T> l): _capacity(l.size()), _size(0) { _array = new T[_capacity]; for(auto e : l) _array[_size++] = e; } Vector<T>& operator=(initializer_list<T> l) { delete[] _array; size_t i = 0; for (auto e : l) _array[i++] = e; return *this; } // ... private: T* _array; size_t _capacity; size_t _size; };
3. 变量类型推导
- 为什么需要类型推导
在定义变量时,必须先给出变量的实际类型,编译器才允许定义,但有些情况下可能不知道需要实际类型怎么给,或者类型写起来特别复杂,比如:
#include <map> #include <string> int main() { short a = 32670; short b = 32670; // c如果给成short,会造成数据丢失,如果能够让编译器根据a+b的结果推导c的实际类型,就不会存 在问题 short c = a + b; std::map<std::string, std::string> m{{"apple", "苹果"}, {"banana","香蕉"}}; // 使用迭代器遍历容器, 迭代器类型太繁琐 std::map<std::string, std::string>::iterator it = m.begin(); while(it != m.end()) { cout<<it->first<<" "<<it->second<<endl; ++it; } return 0; }
C++11中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,可以给程序的书写提供许多方便。将程序中c与it的类型换成auto,程序可以通过编译,而且更加简洁。
decltype类型推导
auto使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。但有时候可能需要根据表达式运行完成之后结果的类型进行推导,因为编译期间,代码不会运行,此时auto也就无能为力。
template<class T1, class T2> T1 Add(const T1& left, const T2& right) { return left + right; }
使用:
decltype是根据表达式的实际类型推演出定义变量时所用的类型,比如:
- 推演表达式类型作为变量的定义类型
int main() { int a = 10; int b = 20; // 用decltype推演a+b的实际类型,作为定义c的类型 decltype(a+b) c; cout<<typeid(c).name()<<endl; return 0; }
2.推演函数返回值的类型
void* GetMemory(size_t size) { return malloc(size); } int main() { // 如果没有带参数,推导函数的类型 cout << typeid(decltype(GetMemory)).name() << endl; // 如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,不会执行函数 cout << typeid(decltype(GetMemory(0))).name() <<endl; return 0; }
.范围for循环
范围for的本质还是迭代器,要求迭代器支持++和 ==
- 例:
int main() { vector<int> arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; for (auto& e : arr) { e *= 2; } for (auto e : arr) { cout << e << " "; } cout << endl; return 0; }