c++ 学习笔记
IO 库
- istrream(输入流)类型, 提供输入操作。
- ostream(输出流)类型,提供输出操作。
- cin, 一个istream对象,从标准输入读取数据。
- cout,一个ostream对象,向标准输出写入。
- cerr,一个ostream对象,通常用于输出程序错误信息,写入标准错误。
- ">>运算符,从istream对象读取写入数据。
- <<运算符,向ostream对象写入输出数据。
- getline函数,从istream对象读取一行数据,写入给定的string类对象中。
io对象无拷贝或赋值
文件流(定义在fstream头文件中)
文件打开模式
ofstream out("file"); //默认out模式打开文件会清空文件内容
ofstream out2("file", ofstream::out);
//显式指定app模式会保留内容,在文件末尾执行操作
ofstream out3("file", ofstream::out | oftream::app);
string流(定义在sstream中)
容器
迭代器
begin和cbegin函数之间的不同:cbegin函数为c++11新标准引入, 用来支持auto。cbegin返回const迭代器。过去只能显式的声明使用哪种迭代器,现在在调用begin时根据对象是否是常量对象来选择是否返回const类型的迭代器,而调用cbegin时无视容器类型返回const_iterator.
同一容器的两个迭代器可以表示一个范围。
assign
可以用来对容器重新赋值,将右边运算对象的全部值拷贝至调用该函数的容器。
list<string> num;
vector<const char*> oldelm;
num = oldelm; //错误:容器类型不同,无法赋值
num.assign(oldelm.begin(), oldelm.end());
swap
除string和array外,swap前后不改变容器的迭代器、引用和指针,皆指向swap之前的元素。
string的swap会导致这三者失效,而array会真正交换其中的元素。其交换时间与元素数目成正比
insert
insert返回指向插入元素的迭代器。
不同容器的迭代器不可比较
map中的key-value对应是pair类的元素
find和count
find返回所查找元素的迭代器,未找到时返回尾后迭代器。count返回要查找元素出现(可重复容器)的次数,
未找到时返回0.
有序容器的关键字类型
class A{
int mem;
//...
};
bool A::comp(A a,A b){
return a.mem<b.mem;
}
multiset<A, decltype(comp)*>aset(comp); //这样就可以指定自定义的操作
insert的返回值
insert返回的值依赖容器的类型。对于不可重复的关联容器,insert返回一个pair,first为指向插入元素的迭代器,second为一个bool值,若容器中不存在该关键字返回true,存在则插入失败,返回false。
泛型算法
accumulate
type sum = accumulate(v.begin(), v.begin(), m)
accumulate对容器v的元素求和,和的初始值为m。执行的加法依据m的类型,所以m的类型非常关键。
vector<string> v; string sum = accumulate(v.begin(), v.end(), string("")); //正确 //错误, const string* 上未定义+运算符。 string sum = accumulate(v.begin(), v.end(), "");
list这类的特定容器算法
成员函数版本比通用版本性能更优。
lst.merge(lst2, comp); //合并两个有序列表,lst2会被清空
lst.merge(lst2);
lst.remove(val);
lst.remove_if(pred);
lst.sort();
lst.sort(comp);
lst.unique(); //删除连续相同元素,只保留其中一个
lst.unique(comp); //二元谓词
迭代器
back_inserter
插入迭代器,接受一个指向容器的引用,返回与该容器绑定的插入迭代器。具体效果是通过此迭代器赋值时,赋值运算符会调用push_back向容器中添加指定元素。
vector<int> vec;
fill_n(back_inserter(vec), 10, 0); //添加十个元素到容器中
iostream迭代器
istream_iterator<int> inp_it(cin);
istream_iterator<int> eof;
ifstream in("filename");
ostream_iterator out(cout, " "); //每次输出后都会加上一个空格
可以通过inp_it和eof来遍历输入流对象。
unique
unique只会消除相邻近的重复元素。
vector<int> vec = {1,3,3,4,2,3,4,2,2};
unique(vec.begin(), vec.end()); //输出1,3,4,2,3,4,2
sort(vec.begin(), vec.end()); //先对容器内的元素排序
unique(vec.begin(), vec.end()); //再用unique就可以消除所有重复元素
lambda
一个lambda表达式表示一个可调用的代码单元。
可以通过尾置返回类型来指定lambda返回类型。
编译器在处理lambda表达式时,实际上是产生了一个未命名函数类的未命名对象,通过函数调用符来进行调用。
bind
每一个占位符“_n”使用前需要声明。
using std::placeholders::_1;
若果希望传递给bind一个对象(类似ostream)但又不想拷贝它,可以使用标准库ref函数。
动态内存
make_shared(智能指针)
shared_ptr<int> p= make_shared<int>(42);
shared_ptr<string> p2 = make_shared<string>(10, '9');
shared_ptr<int> p3 = make_shared<int>();
auto p4 = make_shared<vector<int>>();
不要用get来初始化另一个智能指针或为智能指针赋值
new
int *i = new int; // i指向一个动态分配的未初始化的无名对象
new在内存中创建一个未初始化的int对象,并返回指向该对象的指针。
默认情况下,动态分配的对象是默认初始化的,类类型的对象则调用该类的构造函数进行初始化,而内置类型和组合类型的对象的值是未定义的。
new创建过程的三步
- 调用名为 operator new或operator new[]的标准库函数来分配足够大的空间
- 对值进行初始化,如果创建的对象是类类型则会调用该类型的构造函数
- 返回指向该对象的指针
括号包围的初始化器
auto i = new auto(obj) //i指向一个与obj类型相同的对象(用obj初始化)
动态分配的const对象
动态分配的常量必须在声明时就进行赋值或者初始化。
内存耗尽
int* p = new nothrow int(42);
当内存不足以分配出足够空间时,会抛出一个bad_alloc异常,而如果加上nothrow则不会抛出异常,而是返回一个空指针。
unique_ptr
给unique_ptr传递自定的删除器时需要在模板参数列表中加入删除器的指针,而shared_ptr则不用。具体如下:
void del(string&);
unique_ptr<string, decltype(del)*> up(new string, del);
shared_ptr<string> sp(new string, del);
weak_ptr
指向shared_ptr控制的对象,可以用来核查指向的对象是否还存在。
shared_ptr<string> s(new string);
weak_ptr<string> wp(s);
wp.use_count(); //返回共享该对象的智能指针数。
wp.expired(); //use_count()为零则为true,否则为false。
wp.lock(); //返回指向该对象的一个shared_ptr, 没有则返回空的shared_ptr.
动态数组
int *p = new int[10];
分配一个动态数组会返回一个元素类型的指针。
我们可以分配一个大小为零的动态数组,但不能解引用其返回指针。
allocate类
allocator<string> alloc;
auto const p = alloc.allocate(10);
auto q = p;
alloc,construct(q++);
alloc.construct(q++, "hi");
alloc.construct(q++, 10, 'c');
while(q!=p)alloc.destroy(--q);
浙公网安备 33010602011771号