局部
比如函数内定义的对象,分配在栈上,离开作用域时释放内存
全局
程序内全局可见,生命周期为整个程序运行期间
动态分配的内存
可见性和生命周期介于局部和全局之间,使用new和delete操作符进行内存的分配和释放
动态分配的内存是无名的,new无法为其分配的对象命名,而是返回一个指向该对象的指针
内存泄漏(memory leak)
void fun()
{
int *p = new int(1);
// delete p;
}
离开函数作用域之前没有调用delete p,指针p是局部的,唯一的指向刚才分配的内存的指针,因此再也没有办法能够取得刚才分配的内存的地址了,也无法释放了
自定义类是否使用new的区别
不使用new
#include <iostream>
using namespace std;
class B {};
class A
{
public:
B fieldB;
};
int main()
{
A a1 = A();
B b = B();
a1.fieldB = b;
A a2 = A();
a2.fieldB = b;
cout << "a1:" << &(a1.fieldB) << endl;
cout << "a2:" << &(a2.fieldB) << endl;
return 0;
}
输出
a1:0x7fff7c5bd2df
a2:0x7fff7c5bd2dd
- 对象a的所有需要的内存在调用构造函数之后就已经全部分配完毕(fieldB这部分内存在A对象上),不论是否对fieldB进行赋值,fieldB所占用的内存大小不会改变
- 虽然a1和a2的fieldB都用b来赋值,但是两者并不是同一个对象(地址不同),每次赋值都产生了一个新的B对象的拷贝
使用new
#include <iostream>
#include <string>
using namespace std;
class B {};
class A
{
public:
B *fieldB;
int *intValue;
};
A Test()
{
A a1 = A();
B b = B();
a1.fieldB = &b;
A a2 = A();
a2.fieldB = &b;
A a3 = A();
a3.fieldB = new B();
A a4 = A();
a4.fieldB = a3.fieldB;
cout << "a1:" << (a1.fieldB) << endl;
cout << "a2:" << (a2.fieldB) << endl;
cout << "a3:" << (a3.fieldB) << endl;
cout << "a4:" << (a4.fieldB) << endl;
A a5 = A();
int i = 4;
a5.intValue = &i;
// 用于覆盖之前栈内存的i的值
int another = 5;
return a5;
}
int main()
{
A a = Test();
cout << "a.intValue:" << (*(a.intValue)) << endl;
return 0;
}
输出
a1:0x7fffb05b95ef
a2:0x7fffb05b95ef
a3:0x1c76e70
a4:0x1c76e70
a.intValue:0
- a1和a2的fieldB指向的是局部变量(分配在栈上),离开main函数作用域则会回收
- a3和a4的fieldB指向同一个new产生的动态对象,离开main函数作用域仍存在
- 指针之间的赋值不会产生对象的拷贝,而是指向同一个对象
- Test中的a指向一个临时对象
i
,离开Test函数后,i
已经被释放,函数外的a指向的地址的值是不确定的(视编译器而定)