02 构造和析构

构造函数和析构函数

没有调用初始化的内存 为 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 private
  • struct 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中查找是否存在该空间。然后回收空间

image-20211015140957253
对于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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值