C++研究之---C++11 新特性
总结C++11新特性的功能用法和注意事项
auto 功能:类型说明符,用于自动获取表达式所属的类型
//1.auto定义的变量必须有初始值 auto item = val1 + val2;//item的初始化为val1和val2相加的结果 //2.声明多个变量,每个变量类型要相同 auto sz = 0,pi = 3.14;//错误:sz和pi类型不一致 //3.使用引用是使用引用的对象 int i = 0, &r = i; auto a = r; // a是一个整数 //4.auto 忽略顶层const,保留底层const const int ci = i,&cr = ci; auto b = ci; //b是一个整数(ci的顶层const特性被忽略掉了) auto d = &i; //d是一个整形指针(整数的地址就是指向整数的指针) auto e = &ci; //e是一个指向整数常量的指针(对常量对象取地址是一种底层const) //一条语句定义多个变量,符号&和*只从属于某个声明符,而非基本数据类型,初始值必须是同一类型 auto k = ci,&l = i;//k是整数,l是整数引用 auto &n = i,*p2 = &ci;//错误,i的类型是int 而&ci的类型是const int
long long 类型 C++语言规定,一个int至少和一个short一样大,一个long至少和一个int一样大,一个long long至少和一个long一样大
列表初始化 用花括号来初始化变量
//各种初始化 int units_sold = 0; int units_sold = {0}; int units_sold{0}; int units_sold(0); //列表初始化如果存在丢失信息的风险,则报错: long double ld = 3.1415926; int a{ld},b = {ld};//错误:转换示执行,因为存在丢失信息的危险 int c(ld),d = ld; //正确:转换执行,丢失部分数值
空指针 nullptr 特殊类型的字面值,可以转换为任意指针类型; C++程序最好使用nullptr,尽量避免使用NULL;
//下面等价 int *p1 = nullptr; int *p2 = 0; //需要#include cstdlib int *p3 = NULL
constexpr 变量 constexpr声明的变量由编译器来验证变量值是否是一个常量表达式; constexpr声明的变量一定是一个常量,而且必须用常量表达式初始化; constexpr声明的类型为字面值类型(算术,引用 和指针),自定义、IO库,string类型不属于。 constexpr指针初始值必须是nullptr或0,或是固定地址的对象(函数体之外的对象)
constexpr int mf = 20;//20是常量表达式 constexpr int limit = mf + 1; //mf +1 是常量表达式 constexpr int sz = size(); //只有当size是一个constexpr函数时才是一条正确的声明语句 //仅对指针有效,与指对象无关 const int *p = nullptr; //p是一个指向整形常量指针 constexpr int *q = nullptr;//q 是一个指向整数的常量指针 //constexpr指针既可以指向常量也可以指向一个非常量 constexpr int *np = nullptr;//np是一个指向号数的常量指针 int j = 0; constexpr int i = 42; //i和j 都必须定义在函数体之外 constexpr const int *p = &i;//p是常量指针,指向整型常量i constexpr int *p1 = &j;、、//p1是常量指针,指向整数j
类型别名using
//传统方法 typedef typedef double wages;//wages是double的同义词 //using using SI = Sales\_item; //SI是Sales\_item的同义词 //指针、常量和类型别名 typedef char *pstring;//pstring 是指向char 的指针 const pstring cstr = 0;//cstr是指向char的常量指针 const pstring *ps;//ps是一个指针,它的对象是指向char的常量指针 //如果理解成:const char *cstr = 0;//是对const pstring cstrr 的错误理解
decltype 类型指示符 选择并返回操作数的数据类型
decltype(f()) sum = x; //sum的类型就是函数f的返回类型 //decltype处理顶层const和引用的方式与auto不同 const int ci = 0,&cj = ci; decltype(ci) x = 0; //x是const int decltype(cj ) y = x; //y是const int&,y绑定到变量x decltype(cj) z; //错误 z是一个引用,必须初始化 //如果decltype使用的表达式不是一个变量,则以返回的表达式结果对应类型 int i = 42,*p = &i,&r = i; decltype(r + 0) b; //正确:加法的结果是int,因此b是一个int decltype(*p) c; //错误:c是int& 必须初始化 //decltype 的表达式如果是加上了括号的变量,结果将是引用 decltype((i)) d;//错误:d是int&,必须初始化 decltype(i) e;//正确:e是一个(未初始化的)int //使用decltype简化函数返回类型 int odd\[\] = {1,3,5}; int even\[\] = {0,2,4}; //返回一个指针,指向含有3个整数的数组 decltype(odd) *arrPtr(int i ){ return (i%2)?&odd:&even; }
类内初始化 初始化和赋值不同,一个是没值,一个是有值
范围for 遍历给定序列中的每个元素并对序列中的每个值执行某种操作
//语法 for(declaration : expression) statement //示例 string str("some string"); for(auto c : str) cout << c <<endl; for(auto &c : s) c = toupper(c);//转为大写
vector对象的vector
vector<vector<int>>
vector对象列表初始化
vector<string> articles = {"a","an","the"}; vector<string> v1("a","an","the");//错误
容器的cbegin和cend函数 类似于begin和end,只是返回的是const_iterator
auto it2 = v.cbegin();//it3的类型是vector<int>::const_iterator
函数begin和end 和容器功能类似,以数组为参数
int ia\[\] = {0,1,2,3,4,5,6,7}; int *beg = begin(ia);//指向首元素的指针 int *last = end(ia);//指向尾元素的下一个位置的指针 //示例 //pbeg指向arr的首元素,pend指向arr的尾元素的下一位置 int \*pbeg = begin(arr),\*pend = end(arr); //寻找第一个负值元素 wile(pbeg != pend && *pbeg >=0) ++pbeg;
除法舍入规则 商一律向0取整(直接切除小数部分)
sizeof用于类成员 使用作用域运算符来获取类成员的大小,sizeof运算符无须提供一个具体的对象。
initializer_list类 标准库类型,用于表示某种特定类型的值的数组
//是一种模板类型,注意元素是常量值 initializer\_list<string> ls;//initializer\_list的元素类型是string initializer_list<int> li; //示例 void error\_msg(initializer\_list<string> il) { for(auto beg = il.begin();beg!= il.end();++beg) cout << *beg << ""; cout <<endl; } //调用 expected 和actual是string对象 if(expected != actual) error_msg({"functionX",expected,actual}); else error_msg({"fuctionX","okay"});
列表初始化返回值 函数可以返回花括号包围的值的列表
vector<string> process() { return {}; //return {"fuctionX","okay"}; }
尾置返回类型 较适用于返回类型比较复杂的函数(数组的指针或数组的引用)
//func接受一个int类型的实参,返回一个指针,该指针指向含有10个整数的数组 auto func(int i)->int (*)\[10\];//注意加括号和不加括号的区别
constexpr函数 能用于常量表达式的函数:函数返回类型及所有形参的类型都得是字面值类型;函数体必须有且只有一条return语句
constexpr int new_sz() {return 42;} constexpr int foo = new_sz();//正确:foo是一个常量表达式 //函数体内也可以包含其他语句,只有这些语句在运行时不执行任何操作(空语句,类型别名,using声明) //如果arg是常量表达式,scale(arg)也是常量表达式 constexpr size\_t scale(size\_t cnt){return new_sz() * cnt} //当scale的实参是常量表达式时,它的返回值也是常量表达式 int arr\[scale(2)\]; //正确 int i = 2; int a2\[scale(i)\]; //错误,scale(i)不是常量表达式
=default 生成默认构造函数 通过在参数列表后面写上=default,要求编译器生成构造函数。可以和声明一起出来在类的内部(内联),也可以作为定义出现在类的外部。
Sales_data() = default;
类对象成员类内初始化
class Window_mgr{ private: //这个Window_mgr追踪的Screen //默认情况下,一个Window_mgr包含一个标准尺寸的空白Screen std::vector<Screen> screens{Screen(24,80,'')}; }
委托构造函数 使用它所属类的其他构造函数执行它自己的初始化过程(把它职责委托给了其他构造函数)
class Sales_data{ public: //非委托构造函数使用对应的实参初始化成员 Sales\_data(std::string s,unsigned cnt,double price):bookNo(s),units\_sold(cnt),revenue(cnt *price){} //委托构造 Sales\_data():Sales\_data("",0,0){}
constexpr构造函数 符合构造函数要求(没有返回语句),符合constexpr函数要求(拥有唯一可执行语句就是返回语句),一般函数是空的。可声明=default或=delete
//constexpr构造函数必须初始化所有数据成员,初始值使用constexpr构造函数或一条常量表达式 class Debug{ public: constexpr Debug(bool b = true):hw(b),io(b),other(b){} constexpr bool any(){return hw||io||other;} } //constexpr构造函数用于生成constexpr对象以及constexpr函数的参数或返回类型 constexpr Debug io_sub(false,true,false); if(io_sub.any()) cerr<<"print appropriate error message"<<endl;
用string对象处理文件名 IO参数可以使用库类型string的对象
array和forward_list容器 与内置数组相比,array是一种更安全、更容易使用的数组类型;array对象的大小是固定的,不支持添加和删除元素以及改变容器的大小操作。 forward_list目标是达到与最好手写的单向链表数据结构相当的性能,没有size操作
容器的cbegin和cend函数 无论容器元素是否是常量,返回值都是const_iterator
auto it3 = v.cbegin(); //it3的类型是vector<int>::const_iterator
容器的列表初始化
list<string> authors = {"M","S","A"}; vector<const char*> art = {"a","an","the"};
容器的非成员函数swap swap操作交换两个相同类型容器的内容。调用后,元素交换(本身未交换,只是交换了两个容器的数据结构)
vector<string> svec1(10); //10个元素 vector<string> svec2(24); swap(svec1,svec2);
容器insert成员的返回类型 insert返回指向第一个新加入元素的迭代器,如果范围为空,不插入任何元素,insert操作会将第一个参数返回。
list<string> lst; auto iter = lst.begin(); while(cin >> word) iter = lst.insert(iter,word);//等价于调用push_front
容器的emplace成员的返回类型 emplace_front,empace和emplace_back 操作构造元素(相对于push或insert拷贝),对应push_front,insert和push_back,将元素旋转在容器的头部、一个指定位置之前或窗口尾部
shrink_to_fit 适用于vector,string和deque,capacity和reserve只适用于vector和string
c.shrink\_to\_fit();//将capacity()减少为与size()相同的大小
string的数值转换函数
int i = 42; string s = to_string(i);//将整数i转换为字符表示形式 double d = stod(s);//将字符串s转换为浮点数 //转换s中以数字开始的第一个子串,结果d = 3.14 string s2 = "pi = 3.14"; d = stod(s2.substr(s2.find\_first\_of("+-.0123456789")));
lambda匿名函数 可调用对象(callable object)(函数,函数指针,重载运算符的类,lambda表达式) lambda:未命名的内联函数,可定义在函数内部
//capture list(捕获列表),通常为空; \[capture list\](parameter list) -> return type{function body} //可忽略参数列表和返回类型,但必包含捕获列表和函数体 //空参数列表,推断返回类型 auto f = \[\] {return 42;}; cout << f() <<endl;//调用 //传参 \[\](const string &a,const string &b){return a.size()< b.size()} //调用示例 stable_sort(words.begin(),words.end(),\[\](const string &a,const string &b){return a.size<b.size();}); //捕获列表 \[sz\](const string &a){ return a.size >=sz;}; //调用find_if auto wc = find_if(words.begin(),words.end(), \[sz\](const string &a){ return a.size >=sz;}) //for_each for_each(wc,words.end(), \[\](const string &s){cout << s << " ";}); cout << endl; //值捕获 void fcn1() { size_t v1 = 42; auto f = \[v1\]{return v1;}; v1 = 0; auto j = f();//j为42; } //引用捕获 void fcn2(){ size_t v1 = 42; auto f2 = \[&v1\]{return v1;}; v1 = 0; auto j = f2();//j为0, } //隐式捕获 //sz为隐式捕获,值捕获方式 wc = find_if(words.begin(),words.end(), \[=\](const string &s){return s.size()>=sz;}) //可变lambda void fcn3(){ size_t v1 = 42; //f可以改变它所捕获的变量的值 auto f = \[v1\]() mutable{return ++v1;}; v1 = 0; auto j = f(); //是为43; } //尾置返回类型 transform(vi.begin(),vi.end(),vi.begin(), \[\](int i) -> int {if(i<0) return -i; else return i;});
标准bind 在functional文件中定义,通用的函数适配器,接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表
auto new Callable = bind(callable,arg_list); //check6是一个可调用对象,接受一个string类型的参数 //并用此string和值6来调用check_size auto check6 = bind(check\_size,\_1,6);//_1参数占位符 string s = "hello"; bool b1 = check6(s);//check6(s)会调用check_size(s,6); //lambada的find_if auto wc = find_if(words.begin(),words.end(),\[sz\](const string &a)) //替换为 auto wc = find\_if(words.begin(),words.end(),bind(check\_size,_1,siz)); //_n为placeholders命名空间所定义,functional头文件中 using std::placeholders::_1; //使用所有的定义 using std::placeholders //bind的参数 //g是一个有两个参数的可调用对象 auto g = bind(f,a,b,\_2,c,\_1); //示例 //g(\_1,\_2) 映射为 //f(a,b,\_2,c\_1) //用bind重排参数顺序 //按单词长度由短到长排序 sort(words.begin(),words.end(),isShorter); //按单词长度由长到短排序 sort(words.begin(),words.end(),bind(isShorter,_2,-1)); //绑定引用参数,ref和cref(const引用类) 定义与functional //为了替换一个引用方式捕获ostream的lambda: //os是一个局部变量,引用一个输出流 //c是一个局部变量,类型为char for_each(words.begin(),words.end(),\[&os,c\](const string &s){os << s << c;}); //相同的函数 ostream &print(ostream &os,const string &s,char c){ return os<<s <<c; } //用bind代替os的捕获是错误的,os不能拷贝 for\_each(words.begin(),words.end(),bind(print,os,\_1, '')); //可以使用标准的ref函数 for\_each(words.begin(),words.end(),bind(print,ref(os),\_1,''));
待续… 汇总自:C++Primer 第五版
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 xue_huashan@163.com
文章标题:C++研究之---C++11 新特性
文章字数:3.5k
本文作者:max-xue
发布时间:2018-08-22, 13:57:02
最后更新:2019-11-09, 21:09:39
原始链接:http://blog.le-more.com/2018/08/22/c++/c11-e6-96-b0-e7-89-b9/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。