C++语言笔记C11库

1.C++函数库

Algorithms 

<algorithm> 

C Library Wrappers 

<cassert> , <cctype><cerrno><cfenv><cfloat><cinttypes><ciso646><climits><clocale><cmath><csetjmp><csignal><cstdarg><cstdbool><cstddef><cstdint><cstdio><cstdlib><cstring><ctgmath><ctime><cwchar><cwctype> 

Containers 

Sequence 

<array> 、<deque><forward_list><list><vector> 

Ordered Associative 

<map> , <set> 

Unordered Associative 

<unordered_map> , <unordered_set> 

Adaptor 

<queue> , <stack> 

Error Handling 

<exception><stdexcept><system_error> 

Input/Output 

<filesystem> , <fstream><iomanip><ios><iosfwd><iostream><istream><ostream><sstream><streambuf><strstream> 

Iterators Library 

<iterator> 单独的迭代器通常用于泛型算法中,而不会单用

Localization 

<codecvt> , <cvt/wbuffer><cvt/wstring><locale> 

Math and Numerics 

<complex> , <limits><numeric><random><ratio><valarray> 

Memory Management 

<allocators> , <memory><new><scoped_allocator> 

Multithreading 

<atomic> , <condition_variable><future><mutex><thread> 

Other Utilities 

<bitset> , <chrono><functional><initializer_list><tuple><type_traits><typeinfo><typeindex><utility> 

Strings and Character Data 

<regex> , <string> 

 

1.C++命名空间
C++只有一个命名空间std,包含了所有的C++库。关于命名空间,同一个命名空间的名字可以在不同的文件或同一文件中多次出现,也可以出现在头文件里面,表示同一命名空间的不同部分代码。

2.C++引用与指针
C++的引用一般用于函数入参和函数返回值。引用和指针其实存在本质的区别,引用就是一个对象的别名,没有分配存储对象指针的存储空间;而指针需要分配一个存储对象指针的存储空间。所以指针和引用一般情况下是没有办法相互转换的。C++中,如果对象没有名字(如用new分配的对象)那么它也不可能有别名,而其他语言(如C#)可以只有别名。

3.C++的模板:针对类型的一种统一操作
C++的模板分为函数模板和类模板,两者声明的形式都一样。
template <class T1,...,class Tn> 函数或类声明
{
函数体或类体
}
函数模板在调用时自动实例化,而类模板必须先实例化(指明类型),才能调用。

4.关于throw的栈展开
throw进行栈展开时会调用很多析构函数或进行很多函数的局部变量回收,直到遇到了catch为止。

5.操作符重载
操作符的本质是一个函数,其重载有两种情况:第一种操作符在类中作为成员函数重载;第二种操作符作为全局函数重载。两种重载方式有一点区别:1)在类中作为成员函数重载,将默认第一个函数入参(双目时为左操作数)为this指向的本类对象,所以在类中重载操作符时,双参在形式上变成了单参。2)基于第一条规则,有些左操作数特殊的操作符(如<<>>等要求左操作数必须为流对象)不能在类中重载。在众多的运算符中,大多对左右操作数是敏感的,不允许左右操作数交换。第一个入参是左操作数,第二个入参是右操作数。

6.友元
在类中定义一个友元函数(或重载的操作符)或友元对象,那么在该友元中可以以‘.’访问该类对象的私有成员,这是在其他非友元作用域里做不到的。
Class A{private :int a ;friend void myfunc(void);}
void myfunc(void)
{
A  myA;
cout<<myA.a;//在非友元作用域中不能这样访问。
}

7.容器
所有容器提供的内置方法绝大部分是与迭代器有关的,大部分泛型算法也与迭代器有关。
迭代器和指针是完全一样的,但是迭代器更安全。
容器在构造时可以使用其他不同类型的容器的迭代器或指针来构造,但是需要保证两种容器或数组的数据类型是一致的。

8.

头文件

容器

说明

<iostream>

istream

Wistream,wostream,wiostream

从流中读写数据

ostream

iostream

<fsteram>

ifstream

Wifstream,Wofstream,wiofstream

从文件中读写数据

ofsteram

fsteram

<sstream>

istringstream

Wistringstream,Wostringstream,wstringstream

字符串流中读取数据(底层没有字符串)

ostringstream

stringstream

在流对象使用中,如果产生任何失败,则其对象为0,否则为非0,相应的错误状态被记录在该对象中。

例:Int a;Cin>>a;如果输入了一个字符,那么将产生错误。则cin==0If (cin) 将为false。其它流都有这种用法。

流的作用:->本质上是字符处理。将字符从不同的底层以多种格式(或方式)输入到内存中来,或者相反。以下是例举的几种流的作用:

(1)以单个字符、字符串、行任意形式存取字符

(2)以整形、浮点型等形式存取字符

wKioL1XpElngE4CEAAClZx9iNEQ694.jpg 

 

9.lambda 函数

返回值类型[可使用的全局变量列表](形参列表){函数体}

如果“可使用的全局变量列表”为“=”,则能使用所有的全局变量

10.顺序容器

特点:根据位置存储和访问容器,容器元素的排列次序与元素值无关,而由元素添加到容器里的次序决定。标准库只定义了三种顺序容器:vector,list,deque.

和三种顺序容器适配器(适配器是以基本的容器类型为底层,通过定义新的操作接口,实现不同的数据操作):stack,queue,priority_queue

容器和容器适配器都只提供了少量操作,大部分操作由泛型算法库提供。

容器的长度都是动态可增长缩短的。

容器元素的类型约束有两点:元素类型必须支持赋值运算和元素类型对象必须可复制。(即不能为引用和流)

迭代器的范围为[iter.begin,iter.end),其编程意义为:当iter.begin== iter.end迭代器范围为空。

 

容器内置的操作主要有:

任意位置任意方式增减元素个数的操作,迭代操作,交换元素操作。

11.关联容器
基本的有4种:map,set,multimap,multiset

map中有个不好的地方:

Map<string,int>word_count;

Int occurs=word_count[foobar];

这样的查找如果foobar键不存在于word_count容器中,那么将会增加一个foobar键,并返回值为0。这是编译语言与解释语言的区别。.find方法提供了判断该键是否存在的方法。

.count方法提供了判断mapmultimap中键个数的方法。

python中能实现的操作,在C++中基本上都有这些功能。没有相应的语法支持,但是可以提供对象内置方法来解决(反射除外)

Set容器提供了insert,count,find,erase等操作。可以使用其他容器的迭代器来构造set容器,只保留不重复的元素集合。

除了容器内置的迭代器以外,C++还提供了3类独立迭代器:

1)插入迭代器
back_inserter,front_inserter,inserter.使用容器构造

2)流迭代器
istream_iterator,ostream_iterator

3)反向迭代器
reverse_iterator

12.指向类成员的指针

Class screen{;}

定义指向数据成员的指针:Int screen::*ptr;定义了一个指向screenint类型成员的指针。

定义指向函数成员的指针:void (screen::*ptr)(void);定义了一个指向类函数的指针

指向类成员的指针可以定义在类中也可以定义在类外。

使用定义在类中的指向类成员的指针:两个新的解引用操作符->*.*,他们能够将成员指针绑定到实际对象。

 

成员函数指针列表 :typedef void (*action)(void);

screen::action screen::menu[]={&screen::home,...}

13.auto自动数据类型

Auto int,double不同,他能推断数据的类型,从而将其转化为推断出的类型。

14.序列for循环

所有能使用iterator的序列都能使用序列for循环

Map<string,int>m{{a,1},{b,2},{c,3}};

For(auto p:m){cout <<p.first<<:<<p.second<<endl;}

15.c98和c11的智能指针

(1)auto_ptr 能够代理new[]和new,能赋值(与unique_ptr的区别),但同一时刻只能有一个auto_ptr管理指针(不能放在容器中,但unique_ptr能保存容器指针),不带有引用计数(c98)

(2)unique_ptr 能够代理new[]和new,不能转让,不允许拷贝构造和拷贝赋值(不能放在容器中,但unique_ptr能保存容器指针),不带有引用计数,可以完全代替scoped_ptr和scoped_array(c11)

(3)shared_ptr能够代理new的指针,实现了引用计数(应该是new int了一个内存用来保存引用计数,当发生shared_ptr赋值时将引用计数加1并将引用计数指针赋给另外一个shared_ptr),支持拷贝和赋值,可以放入容器中且可以保存容器指针(make_share模板函数)(最有价值的指针)(c11)

(4)shared_array代理new[]的指针,shared_array能力有限。一般使用shared_ptr<vector>或vector<shared_ptr>来替代(c11)

(5)weak_ptr 该指针是辅助shared_ptr的,shared_ptr给weak_ptr赋值不会增加引用计数(c11)

(6)boost/smart_ptr.hpp

scoped_ptr 接受new的指针,不能转让(不支持拷贝和复制(私有拷贝和复制函数实现),不放入作容器),且只能在本作用域内使用,与auto_ptr基本相同

scoped_array接受new[]的指针,不能转让(不支持拷贝和复制(私有拷贝和复制函数实现),不能用作容器),且只能在本作用域内使用,可以用vector替代

16.一些需要注意的C++编程细节

(1)环形缓存:
#define SIZE 100
int Buffer[SIZE];
Buffer[i%SIZE]='X'

(2)类的复制控制:
定义private的复制构造函数(如IO类),可以保证该对象只有一个副本。通过设计模式还可以使得该类只被构造一次。
classfa a;
classfa b=a;//其实是调用了classfa的默认复制构造函数 classfa(const classfa &)
string c="ancd" //调用了字符构造函数和复制构造函数。

(3)顺序容器:string,vector,list都可以使用.erase()和insert()在任意位置删除和插入指定迭代器的节点。

(4)友元friend 是不支持继承的。即类A是BASE的友元,但它不会是该BASE 的CHILD的友元。

(5)一个C标准函数:将从流中读出的数据,重新压入流的缓存中,可以通过此函数实现peek()函数
    ungetc( char ch, FILE* f);   //向IO缓存中压入数据
   一次只能压入一个字符

(6)递归:(连接2个链表)
已知两个链表head1 和 head2 各自有序,请把它们合并成一个链表依然有序,这次要求用递归方法进行。 
Node * MergeRecursive(Node *head1 , Node *head2) 

if ( head1 == NULL ) 
return head2 
if ( head2 == NULL) 
return head1 
Node *head = NULL   
if ( head1->data < head2->data ) 

head = head1   
head->next = MergeRecursive(head1->next,head2); 

else 

head = head2   
head->next = MergeRecursive(head1,head2->next); 

return head 
}

(7)引用:
常引用:不能通过引用改变变量的值
int b=1;
const int & a=b;
a=2;//错
b=2;//对

string foo( ); 
void bar(string & s); 
那么下面的表达式将是非法的:
bar(foo( )); 
bar("hello world"); 
    foo()的返回值必然是const string型的,“hello world”也被编译器构造为const string,而把他们用于非const函数入参,编译器将会报错。函数的引用入参应尽量指明为const,这样const和非const的实参都不会报错。
    引用作为函数返回值类型的好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

(8)求一个数中包含的二进制1的个数:
def func(x):
cont=0;
while(x):
  x=x&(x-1)
  cont=cont+1
return cont
求任意数据由二进制表示时包含的1的个数

(9)虚析构函数作用:
将析构函数定义为virtual 这样在用delete删除基类指针时可以运行子类的析构函数。

(10)mutable关键字:在const变量中被改变
c++ 中 mutable关键字申明的变量可以在const申明的函数中改变。
class M
{mutable int a;
void set() const
{a=10;}
}

(11)静态成员:
class M
{
static M a; //correct
M *b;   //correct
M c;     //error
}
静态成员是类的一部分,而不是对象的一部分。

(12)const 用法:
const对象不能调用非const的成员函数和变量;为了使const对象和非const对象都可以调用一个同名函数,可以重载该非const和const成员函数。

(13)c数组:
在c/C++中数组是一种完整的数据类型,同结构体,对象一样:
main( ){
  using namespace std;
  int num[5]={1,2,3,4,5};
  cout <<*((int *)(&num+1)-1) <
  }
  在C语言中,一维数组名表示数组的首地址,而且是一个指针.如上例num,
  对&num,表示指针的指针.意味着这里强制转换为二维数组指针.
  这样 &num+1 等同于 num[5][1],为代码空间. (&num+1)-1表示 num[4][0].即num[4].

char (*a)[3][4] 定义一个数组指针

(14)switch的入参:
switch的参数不能是不能自动转化为整型的参数。
因为switch后面只能带自动转换为整形(包括整形)的类型,比如字符型char,unsigned int等,实数型不能自动转换为整形.可以手动强转实数型(int)double,但是会导致精度的丢失.如果后面要对实数型做选择的话,可以乘以10的倍数,然后进行选择,这样不会丢失精度.但是这样的话就要靠你去手动的控制乘以多少了

(15)sizeof

使用sizeof对变量求所占内存长度时,是对该变量直接求内存长度,需要搞清楚,sizeof的对象是谁。

char *p=“dk4m7”;//sizeof(p),p内存为4字节

char p[]="dk4m7";//sizof(p),p内存为6字节,(p符号相当于一个引用,本身不占内存)

(16)多维数组

char a[2][3][4]={{{1,2,3,4},{5,6,7,8},{9,10,11,12}},{{13,14,15,16},{17,18,19,20},{21,22,23,24}}};

a符号表示一个引用,不占内存。其指向的地址为a[0],a[0][0],&a[0][0][0]

a表示一个3维数组,a+1表示最高维加1,相当于a[1]的首地址

*a表示一个2维数组,*a+2,表示2维数组加1,相当于a[0][2]的首地址

*(a+1)+2相当于a[1][2]的首地址

*(*(a+1)+2)+3相当于a[1][2][3]的首地址

本文出自 “tech记录” 博客,谢绝转载!

你可能感兴趣的:(C++,笔记)