内存分区模型

内存分区模型

2023_4_16_01

new操作符

C++中利用 new 操作符在堆区开辟内存空间用来存放数据
堆区开辟的内存,由程序员手动开辟,手动释放,释放利用操作符 delete

1
语法: new 数据类型

利用new开辟的空间,会返回该空间的首地址

基本用法:

定义一个person类,名字使用动态字符数组在堆内存保存(RAII模式初接触)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <cstring>
using namespace std;
class Person
{
private:
char* name;
int age;
public:
Person():name{},age{}{}
Person(char* name,int age):age{age}{
this->name = new char[strlen(name)+1];//分配堆内存空间
strcpy(this->name,name);
}
char* getName()
{
return name;
}
void setName(const char* n)
{
delete [] name;//释放掉原来名字所占的堆内存空间
name = new char[strlen(n) + 1];
strcpy(this->name,n);
}
int getAge()const
{
return age;
}
void setAge(int age)
{
this->age = age;
}
~Person()
{
delete [] name;//释放堆内存
}
};
int main()
{
Person p{"ethaniel",20};
cout << "p的name:" << p.getName() << " p的年龄:" << p.getAge() << endl;
return 0;
}

引用

作用:给变量起别名

语法: 数据类型 &别名 = 原名;

1
2
3
4
5
int a = 10;
int &b = a;
cout << "a: " << a << " b: " << b << endl;// 10 10
b = 100;
cout << "a: " << a << " b: " << b << endl;// 100 100

注意事项:
(1)引用必须初始化
(2)引用在初始化后,不可以再改变其他变量的别名

做函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void mySwap1(int a,int b)//值传递
{
int temp = a;
a = b;
b = temp;
}
void mySwap2(int *a,int *b)//地址传递
{
int temp = *a;
*a = *b;
*b = temp;
}
void mySwap3(int &a,int &b)//引用传递
{
int temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
mySwap1(a,b);
cout << a <<","<< b << endl;// 10,20
mySwap2(&a,&b);
cout << a <<","<< b << endl;// 20,10
mySwap3(a,b);
cout << a <<","<< b << endl;// 10,20
return 0;
}

作用:函数传参时,可以利用引用的技术让形参修改实参
优点:可以简化指针修改实参

做函数返回值

作用:引用是可以作为函数的返回值存在的
注意:不要反回局部变量引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int& test()
{
//静态变量,放在全局区,系统释放
static int a = 10;
return a;
}
int main()
{
int &ref = test();
cout << "ref = " << ref << endl;
//函数的返回值是引用,可以作为左值
test() = 1000;
cout << "ref = " << ref << endl;
return 0;
}

引用的本质

本质:引用的本质在C++内部实现是一个指针常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//发现是引用,转换为 int* const ref = &a;
void func(int& ref)
{
ref = 100;//ref是引用,转换为*ref = 100
}
int main()
{
int a = 10;
cout << &a << endl;//0x61fe44
//自动类型转换为int* const ref = &a;
//指针常量是指针指向不可改,也说明为什么引用不可更改
int& ref = a;
ref = 20;
cout << a << endl;//20
cout << ref << endl;//20
func(a);
cout << a << endl;//100
cout << ref << endl;//100
return 0;
}

常量引用

1
2
3
4
5
6
7
8
9
10
int a = 10;
//报错,引用必须是一个合法的空间
//int &ref = 10;

//加上const之后,编译器将修改代码
//int temp = 10; const int & ref = temp;
const int &ref = 10;

//通过别名ref修改值
//ref = 20;//报错,加入const之后,变成常量,不能修改

作用:常量引用主要用来修饰形参,防止误操作在函数形参列表中,可以加const修饰形参,防止形参改变实参

静态成员

static修饰成员

静态成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Student
{
public:
static int age;
private:
static string name;
};
//类内声明,类外初始化
int Student::age = 18;
string Student::name = "zs";
int main()
{
Student s1;
//通过对象进行访问
sout << s1.age << endl;//18
Student s2;
s2.age = 20;
sout << s1.age << endl;//20

//静态成员变量,在编译时就存在
//可以通过类名直接进行访问
cout << Student::age << endl;
Student s3;
//静态成员变量也是具有访问权限的
//cout << s3.name << endl; //报错
//cout << Student::name << endl;//报错
return 0;
}

1、一般类内声明,类外初始化
2、所有对象共享同一份数据
3、在编译阶段分配内存
4、静态成员变量也是具有访问权限的

静态成员函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Student
{
public:
static int age;//没有this指针
string name;
public:
static void study()
{
age = 18;
//name = "zs";
cout << "hhxx" <<endl;
}
};
//类内声明,类外初始化
int Student::age = 18;
int main()
{
Student s1;
//通过对象进行访问
s1.study();
//通过类名进行访问
Student::study();
return 0;
}

1、所有对象共享同一个函数
2、静态成员函数只能访问静态成员变量
3、静态成员函数也是具有访问权限的

static修饰成员的应用场景

静态成员变量的应用场景

(1)统计对象的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Student
{
public:
static int count;//静态成员变量
Student(){
count++;//在构造函数中自增
}
};
//类内声明,类外初始化
int Student::count = 0;
int main()
{
Student s1;
Student s2;
Student s3;
//统计对象的数量
cout << Student::count << endl;
return 0;
}

(2)共享数据

(3)常量数据

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student
{
public:
static const int num = 10;
};
int main()
{
Student s1;
cout << s1.num << ednl;
//s1.num = 10; //不能修改

return 0;
}

将一个成员变量声明为静态常量,可以在类的所有对象中共享并且不可修改。

静态成员函数的应用场景

(1)访问静态成员变量

静态成员函数可以直接访问静态成员变量,而不需要创建对象

(2)实现工具函数

1
2
3
4
5
6
7
8
9
10
11
12
13
class MathUtils
{
public:
static int add(const int a,const int b)
{
return a + b;
}
};
int main()
{
cout << "结果" << MathUtils::add(5,3) << endl;
return 0;
}

(3)单例模式

保证一个类只有一个实例,并提供一个全局访问点来获取该实例

实现方式:类的构造函数是私有的

目的:限制类的实例化次数,确保在程序运行过程中只有一个实例存在,避免资源浪费和不一致的状态

具体实现方式:
饿汉式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Singleton
{
private:
Singleton(){}
static Singleton* instance;
public:
static Singleton* getInstance()
{
return instance;
}
};
Singleton* Singleton::instance = new Singleton;//静态成员变量类外初始化,饿汉式
int main()
{
Singleton* s = Singleton::getInstance();
Singleton* s1 = Singleton::getInstance();
if(s == s1)
{
cout << "当前只有一个Singleton实例,即单例模式成立!" << endl;

}else{
cout << "单例模式不成立!" << endl;
}
return 0;
}

懒汉式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Singleton
{
private:
Singleton(){}
static Singleton* instance;
public:
static Singleton* getInstance()
{
if(instance == nullptr)
{
instance = new Singleton;//第一次有人获取对象的时候,才在堆内存中创建唯一实例
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;//静态成员变量类外初始化,懒汉式
int main()
{
Singleton* s = Singleton::getInstance();
Singleton* s1 = Singleton::getInstance();
if(s == s1)
{
cout << "当前只有一个Singleton实例,即单例模式成立!" << endl;

}else{
cout << "单例模式不成立!" << endl;
}
return 0;
}