new/delete【C++动态分配运算符,可以重载】、malloc/free【C语言动态分配函数,不能重载】需要配对使用。
new [] / delete [] 生成和释放对象数组。
#include <iostream>
#include <stdlib.h>
using namespace::std;
class Test{
public:
Test()
: m_val(0)
{
cout << "Test" << endl;
}
~Test(){
cout << "~Test" << endl;
}
private:
int m_val;
};
int main()
{
{
Test a;
}
cout << "end of }" << endl;
Test* pVal = new Test();
delete pVal;
pVal = NULL;
int* p = (int *)malloc(sizeof(int));
free(p);
p = NULL;
Test* pArray = new Test[2]; // 调用两次构造函数
delete[] pArray; // 调用两次析构函数
return 0;
}
-----------------------------------------------------------------
Bss段存放没有初始化或者初始化为0的全局变量。
Data段存放初始化为非零的全局变量。
静态变量在第一次进入作用域时被初始化,以后不必再初始化。
静态成员变量在类之间共享数据,也是放在全局/静态数据区中。并且只有一份拷贝。
#include <iostream>
#include <stdio.h>
int i = 0;
class A
{
public:
int val;
static int nCount;
A() {++nCount;}
~A() {--nCount;}
};
int A::nCount = 0; // 初始化类的静态成员变量
int main()
{
A a;
A b;
printf("Number of A is %d ===>\n\n", A::nCount);
printf("no static variable: 0x%x\n", &a.val);
printf("no static variable: 0x%x\n", &b.val);
printf("static class member: 0x%x\n", &a.nCount);
printf("static class member: 0x%x\n", &b.nCount);
printf("global member: 0x%x\n", &i);
return 0;
}
-----------------------------------------------------------------
rodata存放常量数据。
常量不一定挡在rodata中,有些立即数直接和指令编码在一起,放在text中。
字符串常量,编译器会去掉重复的字符串,保证只有一个副本。
字符串会被编译器自动放到rodata中,加const关键字修饰的全局变量也放在rodata中。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
int main()
{
char* p = "Hello";
char* p2 = "Hello";
// 字符串常量,编译器会去掉重复的字符串,保证只有一个副本
printf("p指向地址 = %p\n", p);
printf("p2指向地址 = %p\n", p2);
if(p == p2)
{
printf("Smart complier, set the string in one place!\n");
}
char* p3 = (char*)malloc(12);
memset(p3, 0, 12); // ACSII码是0表示空格
// 将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值,
// 第一个值为指定的内存地址,块的大小由第三个参数指定,
// 这个函数通常为新申请的内存做初始化工作, 其返回值为指向s的指针。
printf("p3 = %s\n", p3);
printf("p3指向地址 = %p\n", p3);
strcpy(p3, p2);
printf("p3 = %s\n", p3);
p3[1] = 'x';
printf("p3 = %s\n", p3);
free(p3);
p3 = NULL;
// p[1] = 'x'; 会出现段错误,常量字符串是不能修改的
return 0;
}
栈中存储自动变量或局部变量,以及传递的参数等。
堆是用户程序控制的存储区,存储动态产生的数据。
当用malloc/new来申请一块内存或者创建一个对象时,申请的内存在堆上分配,需要记录得到的地址,并且在不需要的时候释放这些内存。
栈一般很小,满足不了程序逻辑的要求。
-----------------------------------------------------------------
#include <iostream>
#include <stdio.h>
class AA{
public:
A() {printf("A created\n");}
~A() {printf("A destroyed\n");}
};
class B{
public:
B() {printf("B created\n");}
~B() {printf("B destroyed\n");}
};
A globalA; // 调用A的构造函数
B globalB; // 调用B的构造函数
int foo(void)
{
printf("\nfoo()---------------->\n");
A localA; // 调用A的构造函数
static B localB; // 调用B的构造函数,因为localB是静态对象,不用再次调用构造函数
printf("foo()<-------------------\n");
return 0; // 至此只调用A的析构函数,静态对象localB生命期未到。
}
int main()
{
printf("main()------------------->\n");
foo();
foo();
printf("main()<-------------------\n");
return 0;
// 至此分别调用B和A的析构函数2次和1次
}
作用域由{}定义,并不一定是整个函数。
------------------------------------------------------------------------------------------
#include <iostream> #include <stdio.h> class A{ public: A() {printf("A created\n");} ~A() {printf("A destroyed\n");} // 拷贝构造函数 A(const A& a) {printf("A created with a copy\n");} }; A *foo(A a) { printf("\nfoo()---------------->\n"); A *p = new A(); // 调用A的构造函数 printf("foo()<-------------------\n"); return p; // 调用A的析构函数(对应32行的拷贝构造函数) } A *boo(const A& a) { printf("\nboo()---------------->\n"); A *p = new A(); // 调用A的构造函数 printf("boo()<-------------------\n"); return p; } int main() { printf("main()---------------->\n"); A a; // 调用A的构造函数 A *p = foo(a); // 传递a的副本,调用A的拷贝构造函数 delete p; // 调用A的析构函数(对应15行的构造函数) p = NULL; p = boo(a); // 传递a的引用 delete p; // 调用A的析构函数(对应23行) p = NULL; printf("main()<----------------\n"); // // 调用A的析构函数(对应31行的构造函数) return 0; }
#include <iostream> #include <stdio.h> class A{ public: A() {printf("A created\n");} ~A() {printf("A destroyed\n");} }; A *CreateA(void) { printf("\nCreateA()---------------->\n"); A *p = new A(); // 调用A的构造函数 printf("\nCreateA()<----------------\n"); return p; } int main() { A *pA = new A(); // 调用A的构造函数 printf("pA = 0x%x\n", pA); delete pA; // 调用A的析构函数 pA = CreateA(); printf("pA = 0x%x\n", pA); delete pA; // 调用A的析构函数 return 0; }