第二周
七、三大函数
1.三大函数
Class without pointer member-complex
Class with pointer member-string
拷贝构造 String s3(s1)
拷贝赋值 s3=s2
如果没有写拷贝构造和拷贝赋值,编译器会给一套,一个位一个位复制。如果编译器给的够用,不用写,比如前面的complex。带指针的类不能用编译器给的默认版本,要自己写。
除了构造函数,还有三大函数:
(1)拷贝构造
(2)拷贝赋值
(3)析构函数(清理动态分配的内存)
2.析构函数
{
String s1()
String s2(“hello”)
String * p = new String(“hello”)
delete p
}
离开作用域自动析构,p为什么手动析构。
3.Class with pointer members必须有copy ctor和copy op=
使用默认拷贝构造或拷贝赋值(浅拷贝)
(1)内存泄漏
(2)两个对象指向同一块内存(alias)
4.拷贝构造函数
深拷贝,要分配足够的空间,把内容拷贝进去。编译器给的默认版本只拷贝指针,浅拷贝。
5.拷贝赋值函数
先把左边内容清空,分配一个和右边一样大的空间,把右边的内容复制进去。
八、堆、栈与内存管理
1.stack和heap
Stack 是存在于某作用域的一块内存空间。当调用函数,函数本身即会形成一块stack来放置它所接收的参数,以及返回地址。在函数本体内声明的任何变量,其所使用的内存块都取自上述stack。
Heap 是指由操作系统提供的一块global内存空间,程序可动态分配从中获得若干区块。
{
Complex c1(1,2);
}
Stack object,其生命在作用域结束之际结束。这种作用域内的object,称为auto object,因为它会被自动清理,自动调用析构函数。
{
Static Complex c2(1,2);
}
Static object,其生命在作用域结束之后仍然存在,直到整个程序结束。
Complex c1(1,2);
int main()
{
}
Global object,其生命在真个程序结束之后才结束。也可以把它视为一种static object,其作用域是整个程序。
Heap object,其生命在它被delete之际结束。如果没有delete,会出现内存泄漏。因为当作用域结束,p所指的heap object仍然存在,但指针p的生命却结束了,作用域之外再也卡不到p,也就没有机会delete p。
补充:C++内存管理
本期专题将从内存管理、内存泄漏、内存回收这三个方面来探讨C++内存管理问题。
http://blog.csdn.net/zhanghefu/article/details/5003407
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
2.new
new,先分配memory,再调用ctor。
第3步怎么调用构造函数?
3.delete
delete:先调用dtor,再释放memory
4.动态分配所得的内存块,in VC
调试模式,vc分配的内存块是16的倍数,52->64
Release mode,16
上下cookie记录整块给的大小,41(应该是40,最后一个bit表示给出去还是收回来
5.动态分配所得的数组
vc用一个整数记录3
array new 一定要搭配array delete
九、复习String类的实现
1.构造函数、拷贝构造和拷贝赋值不能用const成员函数,因为都要赋值,改变了成员数据。
2.拷贝赋值返回值,因为从c习惯延续的连续赋值,所以返回值不能是void,必须是String&。
3.拷贝赋值要判断是不是自我赋值,if(this=&str) return *this。
4.引用(&出现在type name后面)和取地址(&出现在object前面)
十、扩展补充:类模板、函数模板和其他
1.static
this pointer
成员函数只有一份,成员函数都有一个隐藏的参数this pointer,通过this pointer找到它要处理的对象。
static data members
static member functions
静态成员函数没有this pointer,只能处理静态数据。
注意静态成员数据的定义(初始化)。
2.把构造函数放在private区
3.cout
为什么cout能够接受各种类型的对象,操作符<<重载?
4.class template,类模板
编译器会把T全部替换为double,得到一份代码;把T全部替换为int,得到一份代码。使用模板会使代码膨胀(不是缺点)。
5.function template,函数模板
类模板要明确指出type要绑定为什么,函数模板不用明确指出,因为编译器会做实参推导。
C++标准库中的算法都是函数模板。
6.namespace
标准库中所有都包含在std中。
使用标准库中的东西:
using directive
using namespace std;
全部打开
using declaration
using std::cout;
一条一条打开
直接std::cout