1.静态内存,栈内存,堆内存
静态内存用来保存局部static对象、类static数据成员以及定义在任何函数之外的变量。
栈内存用来保存定义在函数内的非static对象。
分配在静态或栈内存中的对象由编译器自动创建和销毁。
对于栈对象,仅在其定义的程序块运行时才存在;static对象在使用之前分配,在程序结束时销毁。
除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称作自由空间或堆。
程序用堆来存储动态分配的对象——即,那些在程序运行时分配的对象。动态对象的生存期由程序来控制,也就是说,当动态对象不再使用时,我们的代码必须显式地销毁它们。
- 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共 享内存,做进程间通信。
- 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 数据段--存储全局数据和静态数据。
- 代码段--可执行的代码/只读常量。
2.new和delete
c++语言定义了两个运算符来分配和释放动态内存。运算符new分配内存,delete释放new分配的内存。
相对于智能指针,使用这两个运算符管理内存非常容易出错,随着我们逐步详细介绍这两个运算符,这一点会更为清楚。
而且,自己直接管理内存的类与使用智能指针的类不同,它们不能依赖类对象拷贝、赋值和销毁操作的任何默认定义。
因此,使用智能指针的程序更容易编写和调试。
2.1.使用 new 动态分配和初始化对象
在自由空间分配的内存是无名的,因此 new 无法为其分配的对象命名,而是返回一个指向该对象的指针:
int*pi = new int; // pi指向一个动态分配的、未初始化的无名对象
此new表达式在自由空间构造一个int型对象,并返回指向该对象的指针。
默认情况下,动态分配的对象是默认初始化的,这意味着内置类型或组合类型的对象的值将是未定义的,而类类型对象将用默认构造函数进行初始化:
string*ps = new string;// 初始化为空 string
int*pi = new int; // pi指向一个未初始化的int
我们可以使用直接初始化方式来初始化一个动态分配的对象。
我们可以使用传统的构造方式(使用圆括号),在新标准下,也可以使用列表初始化(使用花括号):
int *pi = new int(1024); // pi指向的对象的值为1024
string *ps = new string(10,'9'); //*ps 为"9999999999"
// vector有10个元素,值依次从0到9
vector<int> *pv = new vector<int>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
也可以对动态分配的对象进行值初始化,只需在类型名之后跟一对空括号即可;
string *psl new string; //默认初始化为空string
string *ps = new string();// 值初始化为空 string
int *pil =new int;// 默认初始化;*pil的值未定义
int *pi2 = new int(); // 值初始化为 0;*pi2为0
对于定义了自己的构造函数的类类型来说,要求值初始化是没有意义的;不管采用什么形式,对象都会过就认构造函数来初始化.
但对于内置类型,两种形式的差别就很大了;值初始化的内置类型对象有着良好定义的值而默认初始化的对象的值则是未定义的。
类似的,对于类中那些依赖于编译器合成的默认构造函数的内置类型成员,如果它们未在类内被初始化,那么它们的值也是未定义的。
出于与变量初始化相同的原因,对动态分配的对象进行初始化通常是个好主意。
如果我们提供了一个括号包围的初始化器,就可以使用auto从此初始化器来推断我们想要分配的对象的类型。
但是,由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器时才可以使用auto:
auto pi = new auto(obj); // p指向一个与obj类型相同的对象
//该对象用obi进行初始化
auto p2 = new auto{a, b, c}; //错误:括号中只能有单个初始化器
p1的类型是一个指针,指向从obj自动推断出的类型。
若obj是一个int,那么p1就是int*;若obj是一个string,那么pl是一个string*;依此类推。新分配的对象用obj的值进行初始化。
2.2.动态分配的 const 对象
用new分配const对象是合法的
// 分配并初始化一个 const int
const int *pci new const int (1024);
// 分配并默认初始化一个 const 的空 string
const string *pcs = new const string;
类似其他任何const对象,一个动态分配的const对象必须进行初始化。
对于一个定义了默认构造函数的类类型,其const动态对象可以隐式初始化,而其他类型的对象就必须显式初始化。