1 定义一个向量类最基本需要begin、end、size这三个中的两个。
2 定义: template
实体化:vec
3 new T[n]不仅动态分配内存,且还会用 T构造函数进行默认初始化;
上述实体化只有T具有默认构造函数时才有vec
4 库函数提供一些内存分配类,可以直接进行内存分配管理,可以取代new,delete,避免了对构造函数的需要
在自定义向量类中可以将其实体化为内存管理函数,为private类型
5 构造函数有三种:空的、只有大小的 、有大小和初始值的
1 vec(){create();}默认构造函数,空vec类,这里调用create成员函数来清空,首末指针都设置成空指针
2 explicit vec(size_type n,const T& val=T() ) {create(n,val);}
explicit 用来定义带一个参数的构造函数,只有显式使用构造函数时才会有效
2 中有两个构造函数,一个是size_t类型变量做参数的构造函数
一个是size_t和const T&类型变量做参数的构造函数
create为n个类型对象T 分配空间,并赋予初值val,但是初始值必须显式使用,否则T默认构造函数来初始化
6 自定义类型中需要用typedef来定义iterator、const_iterator、size_type、value_type
其中value_type就是内部数据类型,back_inserter由push_back和value_type共同决定。
7 自定义类中,定义索引,T&表示索引 ,T*表示迭代器,这两者都需要定义const和非const两种,begin,end迭代器也需要两种,根据vec类是否是常量来进行选择。
8 复制:隐式即作为参数;
显式即赋值;
隐显复制操作都是由copy constructor复制构造函数完成。
复制构造函数与类名同名的成员函数,复制给同类新对象初始化,只有一个参数,参数与定义类同类型。
多加了后面的create是为了重新建立一个内存防止复制的新对象,否则在一个内存中,一改全改
9 赋值:赋值运算符也属于成员函数,需要返回值,属于public,重点考虑自我赋值的问题
声明:vec& operator=(const vec&);
定义:template
vec
{ if(&rts !=this){
uncreate();//如果不同,释放对象占用的旧内存空间
create(rts.begin(),rts.end());}
return *this;
}
使用:vec
注:声明中表明了const,在定义时可不写。
this只在成员函数内部有效,是指向操作对象的指针,对于二元操作符,this总是指左操作数。
10 注意赋值和初始化的区别:
初始化:1 声明一个变量:string y;
2 在一个函数入口处用到函数参数的时候:plit(words);
3 函数返回中使用函数返回值: v =plit(words);这里还包含了赋值
4 在构造初始化时:string s="abdjvkg";
赋值:“=”出现在表达式中,y=words;
最大的区别:赋值需要清空左操作符的值,释放空间,而初始化不用;
注:构造函数只控制初始化操作,operator=操作只控制赋值操作;
11 析构函数destructor:名字:~+类名,没有参数,没有返回值
public声明:~vec(){uncreate();}
析构函数删除一个指针变量时不会删除指针所指对象的内存。
12 如果自己定义的类没有给赋值运算符函数和析构函数,那么系统会默认自动生成一个版本。默认的操作会根据数据成员或成员函数原本的规则来进行操作。
13 如果类中没有定义任何构造函数,编译器将自动给予一个没有参数的构造函数。最好的定义类时定义一个默认的构造函数,可以显式也可隐式。
14 “三位一体”规则:构造一个类,如果需要一个析构函数,也就可能需要一个复制构造函数和赋值运算符函数。这三个函数统称为内存管理函数。
15 push_back成员函数:系统会重新分配给现在内存两倍的空间,push_back需要grow(),unchecked_append() 两个函数,且这两个函数不用自己写。
public:
void push_back(const T& val)
{ if(avail==limit)
grow();
unchecked_append(val);
}
private:
iterator data;
iterator avail;
iterator limit;
16 内存管理:不采用new和delete,因为受限制很多
自定义类,采用
tempale
class allocator{
public:
T* allocate(size_t); //为T分配内存,返回一个指针
void deallocate(T*,size_t); //释放内存,参数:指针,内存大小
void construct(T*,T); //初始化生成单个对象T
void destory(T*); //删除参数所指对象;
};
void uninitialized_fill(T*,T*,const T&); // 向12区间填充3的对象,相当于初始化
void uninitialized_copy(T*,T*,T*); //将12区间的内容复制到3所指的内存块中,返回3结尾的指针
17 类不变式:(定义类必须满足的条件)
18 create函数是为了分配内存,并初始化,以及正确的设置指针。
uccreate是删除对象,释放内存。
19 delete作用于空指针也可以,但是alloc.deallote需要非零指针做参数
20 标准库类型(library type)ptrdiff_t 与 size_t 类型一样,ptrdiff_t 也是一种与机器相关的类型,在 cstddef 头文件中定义。size_t 是unsigned 类型,而 ptrdiff_t 则是 signed 整型
21 自定义的类,在类限定的范围内可以直接使用,但是超出类范围需要加类的限定词;
22 创建和复制对象时会调用构造函数
23 只有没有定义任何构造函数,编译器才会自动生成一个不带任何参数的构造函数。
24 赋值会先删除原内存单元的值,然后在赋予其新的值。
具体的操作为:自动调用string和vector的复制构造函数对name和homework进行赋值;直接对两个double变量midterm和fin进行赋值;
无论是复制还是赋值,对于string和vector的需要调用复制构造函数,但是double、int等内部类型可以直接复制和赋值
25 习题11-4,析构函数删除了内容但是没有释放内存,只是删除了Student_info中的name,midterm,fainter,homework四个成员函数
26 一个自定义类成分;
public://迭代器(const两)+size_type+value_type
//构造函数+赋值、复制、析构函数、索引、begin、end、size、push_back
private:数据元素、内存分配工具、create、uncreate、grow、unchecked_append
27 vector:数组实现;顺序存储结构,采用预分配策略分配内存;可随机访问元素所以利用索引实现元素访问;仅支持后插故只实现push_back();
list:双向链表实现;采用链式存储结构,不需要预分配;不支持随机访问即不支持索引,利用迭代器++和--以实现遍历;支持前插push_fron()和后插push_back()以及insert()等操作;