C++ 核心编程(一、二) 内存空间与引用
1 内存分区模型
1.1 内存四区
C++ 编程时,内存分成四个部分:代码区、全局区、栈区、堆区。这四个区域在内存中分别成区,并且区和区之间有一定的距离。一般来说,划分内存的时候都是在区里连续划分的。
这几个区分别管理以下的数据:
- 代码区:存放函数体的代码,所有的代码在编译后运行前全部放在代码区中,由操作系统进行直接管理。一般不会涉及到这个区域。
- 全局区:在编译后运行前就存在,存放全局变量(不在函数体中的变量)、静态变量(由 static 修饰的变量)、全局常量(由 const 修饰)、字符串常量。程序运行结束后自动释放。
- 栈区:运行后存在,存放除了全局区以外所有系统自动分配、自动释放的内存空间。一般在函数体运行结束后自动释放。
- 堆区:运行后存在,存放所有程序员控制分配的内存空间。程序员控制分配,程序员控制释放
因为 C++ 有两种创建对象的方式,像创建变量一样创建,或者使用 new 关键字。我做了一个实验。代码如下:
//Person.h
#pragma once
#include<string>
#include<iostream>
class Person {
std::string name;
int year;
public:
Person() ;
Person(std::string, int);
~Person() ;
std::string getName();
void setName(std::string);
int getYear();
void setYear(int);
};
//Person.cpp
#include"Person.h"
using namespace std;
Person::Person() {
cout << "Person constructed." << endl;
name = "No Name.";
year = 0;
}
Person::Person(string name, int year) {
this->name = name;
this->year = year;
cout << "Person constructed." << endl;
}
Person::~Person() {
cout << "Person destoryed." << endl;
}
string Person::getName() {
return name;
}
void Person::setName(string name) {
this->name = name;
}
int Person::getYear() {
return year;
}
void Person::setYear(int year) {
this->year = year;
}
//main.cpp
#include"Person.h"
int main() {
using namespace std;
Person* person1 = new Person("Yangtzi", 22);
Person* person2 = new Person("Irene", 21);
Person person3("AA", 20);
Person person4("BB", 19);
cout << "Address of person1: " << (int)person1 << endl;
cout << "Address of person2: " << (int)person2 << endl;
cout << "Address of person3: " << (int)&person3 << endl;
cout << "Address of person4: " << (int)&person4 << endl;
delete person1;
delete person2;
return 0;
}
最终运行得到结果如下:
Person constructed.
Person constructed.
Person constructed.
Person constructed.
Address of person1: 9040808
Address of person2: 9040568
Address of person3: 3471532
Address of person4: 3471492
Person destoryed.
Person destoryed.
Person destoryed.
Person destoryed.
可以很容易看出来,我们通过 new 关键字创建的对象 person1 和 person2 属于一个内存区域,而用正常的变量创建出来的 person3 和 person4,则属于另一个区域。经过学习我们知道,前者是堆区,后者则是栈区。
1.2 new 运算符
可以通过 new 运算符来在堆区创建基本数据类型、对象、结构。其返回的是一个指针。
int* p = new int(10);
Person* p = new Person();
delete p;
当然,也可以创建一个数组。
int* p[] = new int[10];
delete [] p;
2 引用
2.1 引用的基本使用
作用:给变量起别名
语法:数据类型 &别名 = 原名;
具体实现:引用的本质是指针常量。创建时,必须初始化,并且一旦初始化,不得再修改其指向。
2.2 引用的具体使用
我们之前说,用传址的方法作为参数或返回值可以节约内存空间。而我们也写了,引用的本质是指针常量,所以,使用引用也是一样的。
不过在具体使用的时候要注意两点:
- 不要把局部变量的引用作为返回值(会被释放);
- 返回值可以作为左值;
- 如果不想修改,可以用常量引用,比如
const int& variableName
。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。