第一章:概论:

换句话说,STL所实现的,是依据泛型思维架设起来的一个概念结构。这个以抽象概念(abstract concepts)为主体而非以实际类(classes)为主体的结构,形成了一个严谨的接口标准。在此接口之下,任何组件都有最大的独立性,并以所谓迭代器(iterator)胶合起来,或以所谓配接器(adapter)互相配接,或以所谓仿函数(functor)动态选择某种策略(policy或strategy)。

 STL提供六大组件

1.容器(containers):各种数据结构,如 vector,list,deque,set,map,用来存放数据,详见本书4,5两章。从实现的角度来看,STL容器是一种class template。就体积而言,这一部分很像冰山在海面下的比率。

2.算法(algorithms):各种常用算法如sort,search,copy,erase…详见第6章。从实现的角度来看,STL算法是一种function template。

3.迭代器(iterators):扮演容器与算法之间的胶合剂,是所谓的“泛型指针”,详见第3章。共有五种类型,以及其它衍生变化。从实现的角度来看,迭代器是一种将 operator*,operator->,operatort+,operator--等指针相关操作予以重载的class template。所有STL容器都附带有自己专属的迭代器——是的,只有容器设计者才知道如何遍历自己的元素。原生指针(native pointer)也是一种迭代器。

4.仿函数(functors):行为类似函数,可作为算法的某种策略(policy),详见第7章。从实现的角度来看,仿函数是一种重载了operator()的class或class template.一般函数指针可视为狭义的仿函数。

5.配接器(adapters):一种用来修饰容器(containers)或仿函数(functors)

或迭代器(iterators)接口的东西,详见第8章。例如,STL提供的queue和stack,虽然看似容器,其实只能算是一种容器配接器,因为它们的底部完全借助 deque,所有操作都由底层的deque供应。改变functor接口者,称为function adapter;改变container 接口者,称为container adapter;改变iterator接口者,称为iterator adapter。配接器的实现技术很难一言以蔽之,必须逐一分析,详见第8章。

6.配置器(allocators):负责空间配置与管理,详见第2章。从实现的角度来看,配置器是一个实现了动态空间配置、空间管理、空间释放的class template。

class alloc{

};

 C++11 STL中的容器

==================================================

一、顺序容器:

vector:可变大小数组;

deque:双端队列;

list:双向链表;

forward_list:单向链表;

array:固定大小数组;

string:与vector相似的容器,但专门用于保存字符。

==================================================

二、关联容器:

按关键字有序保存元素:(底层实现为红黑树)

map:关联数组;保存关键字-值对;

set:关键字即值,即只保存关键字的容器;

multimap:关键字可重复的map;

multiset:关键字可重复的set;

--------------------------------------------------------------------------------

无序集合

【不会按字典规则进行排序】

unordered_map:用哈希函数组织的map;

unordered_set:用哈希函数组织的set;

unordered_multimap:哈希组织的map;关键字可以重复出现;

unordered_multiset:哈希组织的set;关键字可以重复出现。

==================================================

三、其他项:

1、stack、queue、valarray、bitset

随机访问中,[ ]与 .at( )功能相同,但是[ ]越界了会直接导致程序崩溃,而 .at( )会抛出异常,故其更安全!

2、size、capacity与shrink_to_fit

size表示目前容器的实际大小、

capacity表示容器的空间,一般 >=size,因为容器初始化或者赋值时,系统会根据情况给予容器一个适当的空间,避免每次增加数据时又得重新新分配空间,索性一次给多点,但也不会很大,

为了节省空间,你可以使用shrink_to_fit将容器空间capacity缩小为size

四、迭代器删除失效:

1. vector,erase(pos),直接把pos+1到finish的数据拷贝到以pos为起点的区间上,也就是vector的长度会逐渐变短,同时iter会逐渐往后移动,直到iter == cont.end(),由于容器中end()返回的迭代器是最后一个元素的下一个(这个地方没有任何值),现在考虑这个状态前一个状态,此时要删除的点是iter, tempIt = iter, ++iter会指向此时的end(),但是执行erase(tempIt)之后,end()向前移动了!!!问题来了,此时iter空了!!!不崩溃才怪。

2. list,erase(pos),干的事情很简单,删除自己,前后的节点连接起来就完了,所以iter自增的过程不会指空,不会崩溃喽。

3. map,erase(pos),干的事情太复杂,但是我们需要知道的信息其实很少。该容器底层实现是RBTree,删除操作分了很多种情形来讨论的,目的是为了维持红黑树性质。但是我们需要知道的就是每个节点类似于list节点,都是单独分配的空间,所以删除一个节点并不会对其他迭代器产生影响,对应到题目中,不会崩溃喽。

4. deque,erase(pos),与vector的erase(pos)有些类似,基于结构的不同导致中间有些步骤不太一致。先说说deque的结构(这个结构本身比较复杂,拣重要说吧,具体看STL源码),它是一个双向开口的连续线性空间,实质是分段连续的,由中控器map维持其整体连续的假象。其实题中只要知道它是双向开口的就够了(可以在头部或尾部增加、删除)。在题中有erase(pos),deque是这样处理的:如果pos之前的元素个数比较少,那么把start到pos-1的数据移到起始地址为start+1的区间内;否则把pos后面的数据移到起始地址为pos的区间内。在题中iter一直往后移动,总会出现后面数据比前面少的时候,这时候问题就和1一样了,必须崩溃!

关联容器(如map, set, multimap,multiset),【不会失效】删除当前的iterator,只会使当前的iterator失效,只要在erase时,递增当前iterator即可。

对于序列式容器(如vector,deque),【会失效】删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator,cont.erase(iter++)可以修改为cont.erase(iter)

list使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator。

五、为不同的容器选择不同删除方式

删除连续容器(vector,deque,string)的元素

 // 当c是vector、string,删除value
c.erase(remove(c.begin(), c.end(), value), c.end()); // 判断value是否满足某个条件,删除
bool assertFun(valuetype);
c.erase(remove_if(c.begin(), c.end(), assertFun), c.end()); // 有时候我们不得不遍历去完成,并删除
for(auto it = c.begin(); it != c.end(); ){
if(assertFun(*it)){
···
it = c.erase(it);
}
else
++it;
} 删除list中某个元素 c.remove(value); // 判断value是否满足某个条件,删除
c.remove(assertFun); 删除关联容器(set,map)中某个元素 c.erase(value) for(auto it = c.begin(); it != c.end(); ){
if(assertFun(*it)){
···
c.erase(it++);
}
else
++it;
}

 各大容器性能对比:

1vector

变长一维数组,连续存放的内存块,有保留内存,堆中分配内存;

支持[]操作,高效率的随机访问;

在最后增加元素时,一般不需要分配内存空间,速度快;在中间或开始操作元素时要进行内存拷贝效率低;

vector高效的原因在于配置了比其所容纳的元素更多的内存,内存重新配置会花很多时间;

vector的内存分配:

一般是按你当时存储数据的两倍开辟空间,当插入数据空间不够时,又会重新增加空间至当时数据空间的2倍,此动作降低了vector的工作效率!!!

注:需要高效的随即存取,而不在乎插入和删除使用vector。

2list

双向链表,内存空间上可能是不连续的,无保留内存,堆中分配内存;

不支持随机存取,开始和结尾元素的访问时间快,其它元素都O(n);

在任何位置安插和删除元素速度都比较快,安插和删除操作不会使其他元素的各个pointer,reference,iterator失效;

注:大量的插入和删除,而不关系随即存取使用list。

3deque

双端队列,在堆上分配内存,一个堆保存几个元素,而堆之间使用指针连接;

支持[]操作,在首端和末端插入和删除元素比较快,在中部插入和删除则比较慢,像是list和vector的结合;

注:关心插入和删除并关心随即存取折中使用deque。

4set&multiset

有序集合,使用平衡二叉树存储,按照给定的排序规则(默认按less排序)对set中的数据进行排序;

set中不允许有重复元素,multiset中运行有重复元素;

两者不支持直接存取元素的操作;

因为是自动排序,查找元素速度比较快;

不能直接改变元素值,否则会打乱原本正确的顺序,必须先下删除旧元素,再插入新的元素。

5map&multimap

字典库,一个值映射成另一个值,使用平衡二叉树存储,按照给定的排序规则对map中的key值进行排序;

map中的key值不允许重复,multimap中的key允许重复;

根据已知的key值查找元素比较快;

插入和删除操作比较慢。

6hash_map

hash_map使用hash表来排列配对,hash表是使用关键字来计算表位置。当这个表的大小合适,并且计算算法合适的情况下,hash表的算法复杂度为O(1)的,但是这是理想的情况下的,如果hash表的关键字计算与表位置存在冲突,那么最坏的复杂度为O(n)。

选用map还是hash_map,关键是看关键字查询操作次数,以及你所需要保证的是查询总体时间还是单个查询的时间。如果是要很多次操作,要求其整体效率,那么使用hash_map,平均处理时间短。如果是少数次的操作,使用 hash_map可能造成不确定的O(N),那么使用平均处理时间相对较慢、单次处理时间恒定的map,便更好些。

 STL容器对比: 

vector

deque

list

set

multiset

map

multimap

名称

向量容器

双向队列容器

列表容器

集合

多重集合

映射

多重映射

内部数

据结构

连续存储的数组形式(一端开口的组)

连续或分段连续存储数组(两端

开口的数组)

双向环状链表

红黑树(平衡检索二叉树)

红黑树

红黑树

红黑树

特  点

获取元素效率很高,插入和删除的

效率很低

获取元素效率较高,插入和删除的效率较高

获取元素效率很低,插入和删除的效率很高

1.键(关键字)和值(数据)相等(就是模版只有一个参数,键和值合起来)

2.键唯一

3.元素默认按升序排列

1.键和值相等

2.键可以不唯一

3.元素默认按升序排列

1.键和值分开(模版有两个参数,前面是键后面是值)

2.键唯一

3.元素默认按键的升序排列

1.键和值分开

2.键可以不唯一

3.元素默认按键的升序排列

头文件

#include <vector>

#include <deque>

#include <list>

#include <set>

#include <set>

#include <map>

#include <map>

操作元素的方式

下标运算符:[0](可以用迭代器,但插入删除操作时会失效)

下标运算符或迭代器

只能用迭代器(不断用变量值来递推新值,相当于指针),不支持使用下标运算符

迭代器

迭代器

迭代器

迭代器

插入删除操作迭代器是否失效

插入和删除元素都会使迭代器失效

插入任何元素都会使迭代器失效。删除头和尾元素,指向被删除节点迭代器失效,而删除中间元素会使所有迭代器失效

插入,迭代器不会失效。删除,指向被删除节点迭代器失效

插入,迭代器不会失效。删除,指向被删除节点迭代器失效

插入,迭代器不会失效。删除,指向被删除节点迭代器失效

插入,迭代器不会失效。删除,指向被删除节点迭代器失效

插入,迭代器不会失效。删除,指向被删除节点迭代器失效

 总结:

vector

deque

list

set

multiset

map

multimap

典型内存结构

单端数组

双端数组

双向链表

二叉树

二叉树

二叉树

二叉树

可随机存取

对 key 而言:不是

vector

deque

list

set

multiset

map

multimap

元素搜寻速度

非常慢

对 key 而言:快

对 key 而言:快

元素安插移除

尾端

头尾两端

任何位置

-

-

-

-

 容器自定义比较方式:

 struct fruit
{
string name;
int price;
friend bool operator <(fruit fl, fruit f2)
{
return fl. price>f2. price;
}
};

 STL容器新颖使用

将数组中的值直接付给容器

int arry[size] = {0,1,2,3,4,5,6};

xxx<int>contain(arry, arry+size);//即将数组中的值直接初始化赋予了容器中

 简介SGI

vector:

 class alloc{

 };

 template <class T,class Alloc=alloc>

 class vector{

 public:

     void swap(vector<T,Alloc>&){

         cout<<"swap()"<< endl;

     }

 };

 vector<int>x,y;

 template <class T,class Alloc=alloc>
class vector{
public:
    typedef T value_type;
    typedef value_type* iterator;
    template <class I>
    void insert(iterator position,I first,I last){
        cout <<"insert()"<< endl;
    }
};
vector<int>x;
vector<int>::iterator ite;

stack:

 template <class T,clase A1loc=alloc,size_t BufSiz=>

 class deque{

 public:

     deque(){

         cout <<"deque"<< endl;

     }

 };

 //根据前一个参数值T,设定下一个参数Sequence的默认值为deque<T>

 template <class T,claas Sequence= deque<T>>

 class stack{

 public:

     stack(){

         cout <<"stack"<< end1;

     }

 private:

     Sequence c;

 };

 stack<int>x;

 template <class T,class Alloc=alloc,size_t BufSiz=>
class deque{
public:
    deque(){
        cout <<"deque"<<'';
    }
}; template <class T,class Sequence>
class stack; template <class T,class Sequence>
bool operator==(const stack<T,Sequence>&x,const stack<T,Sequence>&y); template <class T,class Sequence>
bool operator<(const stack<T,Sequence>&x,const stack<T,Sequence>&y); template <class T,class Sequence=deque<T>>
class stack{
    //写成这样是可以的
    friend bool operator==<T>(const stack<T>&,const stack<T>&);
    friend bool operator< <T>(const stack<T>&,const stack<T>&);
    //写成这样也是可以的
    friend bool operator==<T> (const stack&,const stack&);
    friend bool operator< <T> (const stack&,const stack&);
    //写成这样也是可以的
    friend bool operator==<> (const stack&,const stack&);
    friend bool operator<<>(const stack&,const stack&);
    //写成这样就不可以
    //friend bool operator==(const stack&,const stack&);
    //friend bool operator<(const stack&,const stack&);
public:
    stack(){cout <<"stack"<<endl;} private:
    Sequence c;
}; template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>&y){
    return cout <<"operator=="<<'\t';
}
template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>&y){
    return cout <<"operator<"<<'\t';
}
int main(){
    stack<int>x;//deque stack
    stack<int>y;//deque stack
    cout <<(x==y)<<endl;//operator==1
    cout <<(x<y)<<end1;//operator<1
    
    stack<char>y1;//deque stack
    //cout c<(x== y1)<< endl; //error: no match for...
    //cout <<(x< y1)<< end1;//error: no match for...
}

deque:

 inline sizet _deque_buf_size(size_t n,size_t sz){

     return n!=?n:(sz<?size_t(/sz):size_t());

 }

 template <class T,class Ref,class Ptr,size_t BufSiz>

 struct _deque_iterator{

     typedef _deque_iterator<T,T&,T*,BufSiz> iterator;

     typedef __deque_iterator<T,const T&,const T*,BufSiz>const_iterator;

     static size_t buffer_size(){

         return deque_ buf_size(Bufsiz,sizeof(T));

     }

 };

 template <class T,class Alloc=alloc,size_t Buf8iz=>

 class deque{

     typedef deque_iterator<T,T&,T*,BufSiz> iterator;

 };

 cout << deque<int>::iterator::buffer_size()<<end1;//

 cout << deque<int,alloc,>::iterator::buffer_size()<<endl;//

 第二章、空间配置:

(1)考虑到小型区块所可能造成的内存破碎问题,SGI设计了双层配置器,第一级配置器直接使用malloc和free,第二级配置器则视情况采用不用的策略(需求区块是否大于128bytes)。

第一级适配器以malloc(),free(),reaclloc()等C函数执行实际的内存配置、释放、重配置操作。第二级配置器多了一些机制,避免太多小额区块造成内存的碎片。

SGI第二级配置器的做法是,如果区块够大,超过128字节时,就移交第一级配置器处理。当区块小于128字节时,则以内存池(memory pool)管理,此法又称为次层配置(sub-allocation):每次配置一大块内存,并维护对应的自由链表(free-list)。下次若再有相同大小的内存需求,就直接从free-lists中拔出。如果没有,则向系统要一大块内存,然后做切割,此时切割出来的小内存块,不带cookie。如果客户端释放小额区块,就由配置器回收。为方便管理,任何小额区块的内存需求量上调至8的倍数,并维护16个free-lists,各自管理大小分别为8,16,24...128字节。

在G4.9中编译器使用的是不作任何优化的空间配置器,如果需要制定,则需要指明第二参数:

vector<string, __gnu_cxx::__pool_alloc<string>> vec;

如果free-list中没有可用的区块,将区块大小上调至8的倍数边界,然后调用refill(),准备为free-list重新填充空间。refill()之后介绍。

空间的释放,大于128字节就调用第一级配置器,小于128字节就找出对应的free list,将区块回收。

refill()重新填充空间,新的空间将取自内存池(经由chunk_alloc()完成)。内存池实际操练结果如下图:

(2)第一级配置器直接调用C函数执行实际的内存操作,并实现类似C++ new handler的机制。

(3)当区块超过128bytes时,视之为足够大,便调用第一级配置器。当配置器小于128bytes时,视之为过小,便采用内存池的方式。每次配置一大块内存,并维护对应之自由链表,下次若再有相同大小的内存需求,就直接从free-list中拔出。如果客端释还小额区块,就由配置器回收到free-list中。为了方便管理,SGI第二季配置器会主动将任何小额区块的内存需求量上调至8的倍数(例如客端要求30bytes,就自动调整为32bytes),并维护16个free-list,大小分别是8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128bytes。

(4)内存池

如果水量充足,就直接调出20个区块返回给free-list,如果不够20则返回不足实际个数。如果一个都拿不出,则调用malloc配置40个区块的空间,其中20个给free-list,剩下的20个留在内存池。如果malloc分配失败,则调用第一级配置器。因为第一级配置器有new-handler机制,获取能够整理出多余的空间。、

(5)内存基本处理工具

uninitialized_copy,uninitialized_fill,uninitialized_fill_n,能够将内存配置与对象构造行为分离开来。并且会对POD(即标量型别或传统C struct)对象采用最有效率的初值填写手法,而对non-POD型别采取最保险安全的做法。

为了细化分工,STL allocator将两阶段操作区分开来。内存配置操作由alloc::allocate()负责,内存释放操作由alloc::deallocate()负责;对象构造操作由::construct负责,对象析构操作由::destroy()负责。

  • 内存池:

当申请空间不充足时,系统首先将剩余的空间尽量为你申请出来

一般新申请的空间大小为你所需求空间大小的2倍加上一个随机配置次数增加愈加增大的附加量

 第三章、迭代器概念

STL的中心思想在于:将数据容器(containers)和算法(algorithms)分开,彼此独立设计,最后再以一帖胶着剂将它们撮合在一起。

迭代器相应型别:

迭代器相应型别之一:value type:

所谓 value type,是指迭代器所指对象的型别。任何一个打算与STL算法有完美搭配的class,都应该定义自己的vlue type内嵌型别,做法就像上节所述。

迭代器相应型别之二:difference type:

difference type用来表示两个迭代器之间的距离,因此它也可以用来表示一个容器的最大容量,因为对于连续空间的容器而言,头尾之间的距离就是其最大容量。

如果一个泛型算法提供计数功能,例如STL的count(),其传回值就必须使用迭代器的diference type:

迭代器相应型别之三:reference type

从“迭代器所指之物的内容是否允许改变”的角度观之,迭代器分为两种:

不允许改变“所指对象之内容”者,称为constant iterators,例如 const int *pic;【视为不可改的右值】

允许改变“所指对象之内容”者,称为mutable iterators,例如int *pi。当我们对一个mutable iterators进行提领操作时,获得的不应该是一个右值(rvalue),应该是一个左值(lvalue),因为右值不允许赋值操作(assignment),左值才允许:

int *pi=new int(5);

const int *pci=new int(9);

*pi=7;//对mutable iterator进行提领操作时,获得的应该是个左值,允许赋值

*pci=1;//这个操作不允许,因为pci是个constant iterator,

//提领pci所得结果,是个右值,不允许被赋值

迭代器相应型别之四:pointer type

pointers和references在C++中有非常密切的关联。如果“传回一个左值,令它代表p所指之物”是可能的,那么“传回一个左值,令它代表p所指之物的地址”也一定可以。也就是说,我们能够传回一个pointer,指向迭代器所指之物。

迭代器相应型别之五:iterator_category

最后一个(第五个)迭代器的相应型别会引发较大规模的写代码工程。在那之前,我必须先讨论迭代器的分类。

根据移动特性与施行操作,迭代器被分为五类:

·Input lterator:这种迭代器所指的对象,不允许外界改变。只读(read only)。

·Output terator:唯写(write only)。

·Forward lterator:允许“写入型”算法(例如replace())在此种迭代器所形成的区间上进行读写操作。

·Bidirectiona lterator:可双向移动。某些算法需要逆向走访某个迭代器区间(例如逆向拷贝某范围内的元素),可以使用Biairectional lterators。

·Random Access lterator:前四种迭代器都只供应一部分指针算术能力(前三种支持 operator++,第四种再加上operator--),第五种则涵盖所有指针算术能力,包括p+n,p-n,p[n],pl-p2,p1<p2。

《STL源码剖析》——第一、二、三章的更多相关文章

  1. 《STL源码剖析》——第四章、序列容器

     1.容器的概观与分类 所谓序列式容器,其中的元素都可序(ordered)[比如可以使用sort进行排序],但未必有序(sorted).C++语言本身提供了一个序列式容器array,STL另外再提供v ...

  2. 重温《STL源码剖析》笔记 第二章

    源码之前,了无秘密. --侯杰 第二章:空间配置器 allocator SGI特殊的空间配置器,std::alloc SGI是以malloc()和free()完成内存的配置与释放. SGI设计了双层级 ...

  3. c++ stl源码剖析学习笔记(三)容器 vector

    stl中容器有很多种 最简单的应该算是vector 一个空间连续的数组 他的构造函数有多个 以其中 template<typename T> vector(size_type n,cons ...

  4. 面试题总结(三)、《STL源码剖析》相关面试题总结

    声明:本文主要探讨与STL实现相关的面试题,主要参考侯捷的<STL源码剖析>,每一个知识点讨论力求简洁,便于记忆,但讨论深度有限,如要深入研究可点击参考链接,希望对正在找工作的同学有点帮助 ...

  5. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  6. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  7. STL源码剖析读书笔记之vector

    STL源码剖析读书笔记之vector 1.vector概述 vector是一种序列式容器,我的理解是vector就像数组.但是数组有一个很大的问题就是当我们分配 一个一定大小的数组的时候,起初也许我们 ...

  8. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  9. 《STL源码剖析》读书笔记

    转载:https://www.cnblogs.com/xiaoyi115/p/3721922.html 直接逼入正题. Standard Template Library简称STL.STL可分为容器( ...

  10. 通读《STL源码剖析》之后的一点读书笔记

    直接逼入正题. Standard Template Library简称STL.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adap ...

随机推荐

  1. 06-JavaScript简介

    ### 前段三大块 ```HTML css JavaScript``` ### 什么是JavaScript? JavaScript是运行在浏览器端的脚步语言,JavaScript主要解决的是前端与用户 ...

  2. express快速入门

    1.简介: express是基于Node.js平台,快速开放极简的web开发框架,使用 各种http使用工具和中间件,创建强大API. 2.安装 npm install express -g 全局安装 ...

  3. 《图解HTTP》阅读总结

    前言:<图解HTTP>是一本图文并茂的好书,讲解地很详尽.目前我只完整地读了一遍,很多地方知其然不知其所以然,接下来打算抽空再读一次.这篇博文只是做个粗略记录,第二遍读完会再来编辑细化. ...

  4. React-请求篇

    请求方式: (1)后台API:HttpPost   [FromForm] UserRetisterDTO dto 前端请求: { body:qs.stringify(dto),      header ...

  5. openstack stein部署手册 5. placement

    # 建立数据库用户及权限 create database placement; grant all privileges on placement.* to placement@'localhost' ...

  6. Archlinux笔记本安装手记

    最近看着Linux Mint里一揽子乱七八糟的应用和散布各处的配置文件愈发烦躁,便想体验下大名鼎鼎的Arch,网上的帖子们把Arch Linux的安装难度描述的非常可怕,但实际上跟着Wiki一步一步来 ...

  7. C# 列出并删除一个文件夹下的所有MD5值相同的文件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  8. 使用GDB调试时attach ID不被允许

    在进入gdb后,直接使用attach ID,出现下面的情况: Could not attach to process.  If your uid matches the uid of the targ ...

  9. bzoj4543 [POI2014]Hotel加强版 长链剖分+树形DP

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4543 题解 这道题的弱化版 bzoj3522 [POI2014]Hotel 的做法有好几种吧. ...

  10. flask之路径与函数的映射

    一:运行报错 OSError: [Errno 98] Address already in use:5000端口可能被占 lsof -i:端口号  查看端口被那个进程使用,结果是python3.5 k ...