构造函数和析构函数
没有调用初始化的内存 为 0xcd 而两个0xcd 连续出现就是 中文字符 烫 (debug 模式下)
从网上总结了一下地址的信息,最主要的是:
0xCDCDCDCD 堆上分配的地址,但是没有初始化
0xDDDDDDDD 堆上释放的地址。
0xFDFDFDFD 堆内存的边界
0xCCCCCCCC 栈上分配的内存,但是没有初始化
构造函数 constructor 没有返回类型
class Obj{
public:
Obj();
};
// 构造函数可以有参数
class Obj{
public:
Obj(int i);
};
析构函数 destructor
class Obj{
public:
~Obj();
};
析构函数不能有参数
对象初始化
storage allocation
The compiler allocates all the storage for a scope at the opening brace of that scope.
The constructor call doesn’t happen until the sequence point where the object is defined.
在大括号时就分配了空间,但是构造函数的调用是在对象初始化的时候
没有经历过构造函数则无法析构
在cpp中class 和c的struct 结构类似 都可以用来定义类,但有细微差别
class和struct的区别
class
defaults to privatestruct
defaults to public首选class 。过于简单的类就使用struct
struct Obj { int i; float f; char C; };
Obj x1={1, 2.2,'c' };
Obj xList[3] = { {1, 1.1, 'a'}, {2,2.2, 'b'} };// 第三个x 初始化使用默认值 0,0.0,0
struct Obj2 { float f; int i; Obj2(int a); }; // Obj2()是构造函数
Obj2 y1[] = { Obj2(1), Obj2(2), Obj2(3) }; // 调用Obj2的构造函数
default constructor 是没有参数的构造函数 ,有参数的就不是default constructor。
Obj2 y1[ ]={ Obj2(1), Obj2(2), Obj2(3)};
Obj2 y2[2]={Obj2(1)}; // 是错误的 因为Obj2没有default constructor 无法完成第二个单元元素的构造
#include<stdio.h>
class Obj{
public:
Obj(int a);
~Obj();
int i;
void func();
};
Obj::Obj(int a){
i = a;
printf("Obj::Obj() -- this=%p\n", this);
}
Obj::~Obj(){
printf("here is Obj::~Obj()\n");
}
int main(){
Obj y2[2] ={Obj(3)};
}
编译会报错
default_constructor_constrast.cpp:19:16: error: could not convert ‘()’ from ‘’ to ‘Obj’
Obj y2[2] ={Obj(3)};
^因为Obj没有default constructor 无法完成第二个单元元素的构造
class Obj{
public:
float f;
int i;
Obj(int a);
Obj();
};
Obj::Obj(){ // 添加default_constructor
i=0;
}
Obj::Obj(int i){
this->i = i;
}
int main(){
Obj y2[2] = {Obj(1)}; // 拥有 default_constructor 故编译不报错
return 0;
}
new && delete
在堆里面动态分配内存。和c中的malloc和free类似
先构造再new,
new要做两件事情:1, 分配空间,对int这类数据类型就足够了。2,对应类需要做第二件事,调用类的构造函数。
new运算符返回的结果是地址
delete // 只调用首元素的析构
delete[] // 根据数组里的个数依次调用析构 在使用new []后使用
// delete的时候是先析构 在释放空间
new的时候 会在堆里面给程序分配内存(如果不是特殊的堆分配,则是由编译器分配的,因为os会给编译器分配一定堆空间)。分配后会在一个table中记录分配的地址和空间大小。然后调用其构造函数初始化对象
delete的时候。首先调用析构。根据要删除的空间地址,在table中查找是否存在该空间。然后回收空间
对于r来说,先调用r所指对象的析构,就是只调用了一个对象的析构,但空间都收回了,因为回收空间
加上[] 后 他会保证 r是数组 ,拿到数组的个数 依次把析构做完。
此处需要重看一下视频
new 和不 new的区别
1.new创建类对象需要指针接收,一处初始化,多处使用
2.new创建类对象使用完需delete销毁
3.new创建对象直接使用堆空间,而局部变量不用new定义类对象则使用栈空间
4.new对象指针用途广泛,比如作为函数返回值、函数参数等
5.频繁调用场合并不适合new,就像new申请和释放内存一样
堆和栈空间区域的区别
char* GetString(void) {
char p[] = "hello world";
return p; //此处编译器会提出warning
}// 这种 p是在栈上分配内存,函数结束后将会自动释放,p指向的内存区域内容不是”hello world”,而是未知的内容。
char* GetString(void) {
char* p = "hello world";
return p;
}// 第二种是返回静态存储的内存,这里的”hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。
// 无论什么时候调用GetString,均返回一个“只读”的内存块。
new[] delete[]实例
#include<iostream>
using namespace std;
class Obj {
private:
int i;
int *p;
public:
Obj() { p=0; cout << "Obj::Obj()" << endl; } // p 指针初始化 将其指向null
~Obj(){ if(p) delete p; cout << "Obj::~Obj() i = "<< i << endl;}
// 如果p不为空(经历 f_new_int 函数的调用 拥有new过程),则delete p,
// 如果没有new过程,p 指向null,则不会使用delete(前提是需要将指针初始化)。
void set(int ii) { i = ii; }
void f_new_int() {p = new int; }
void g(Obj* q) { cout << "Obj::g(),q->i = " << q->i << endl; }
};
int main(){
Obj *p = new Obj[10];
for ( int i=0; i<10; i++ )
p[i].set(i);
delete[] p;
}