程序的内存分配
#include <iostream> #include <vector> #include <algorithm> using namespace std;
int global_data = 1; static int global_static_data = 1;
int* stack_data() { int d = 2; return &d; }
int * heap_data() { int* e = new int(6); return e; }
int static_data() { static int sti = 1; return sti; }
int main() {
int* heap_ptr = heap_data(); cout << "局部变量(堆区)访问: " << *heap_ptr << endl;
int static_local_data = static_data(); int local_data = 8; cout << "static_local_data: " << (uintptr_t)&static_local_data << endl; cout << "static_global_data: " <<(uintptr_t) &global_static_data << endl; cout << "global_data: " << (uintptr_t)&global_data << endl; cout << "local_data: " << (uintptr_t)&local_data << endl; return 0; }
局部变量(堆区)访问: 6 static_local_data: 140724477297976 static_global_data: 94198146936852 global_data: 94198146936848 local_data: 140724477297980
|
在C++中,内存通常被划分为几个不同的区域,每个区域都有其特定的用途。以下是C++中常见的内存区域及其特点:
栈区(Stack)
• 特点:
◦ 栈区用于存储局部变量、函数参数、函数调用的返回地址等。
◦ 内存分配和释放由编译器自动管理,遵循“后进先出”(LIFO)的原则。
◦ 栈区的内存分配速度快,但大小有限,通常较小(几MB)。
◦ 当函数调用结束时,栈上的局部变量会自动被销毁。
• 示例:
void foo() { int x = 10; }
|
堆区(Heap)
• 特点:
◦ 堆区用于动态内存分配,程序员可以手动控制内存的分配和释放。
◦ 堆区的内存分配速度较慢,但大小通常较大(受系统内存限制)。
◦ 内存的分配和释放需要通过 new
和 delete
(或 malloc
和 free
)来手动管理。
◦ 如果不手动释放内存,可能会导致内存泄漏。
• 示例:
int* p = new int(10); delete p;
|
全局区(Global/Static Area)
• 特点:
◦ 全局区用于存储全局变量和静态变量(包括静态局部变量和静态类成员变量)。
◦ 全局变量和静态变量的生命周期贯穿整个程序的运行时间。
◦ 全局区在程序启动时分配内存,在程序结束时释放内存。
◦ 全局区通常分为两个部分:data
段(已初始化的全局/静态变量)和 bss
段(未初始化的全局/静态变量)。
• 示例:
int globalVar = 10; void foo() { static int staticVar = 20; }
|
代码区(Text/Code Segment)
• 特点:
◦ 代码区用于存储程序的二进制代码(即编译后的机器指令)。
◦ 代码区通常是只读的,防止程序在运行时意外修改指令。
◦ 代码区的大小在编译时确定,且在程序运行期间不会改变。
• 示例:
常量区(Constant Area)
• 特点:
◦ 常量区用于存储字符串常量和全局常量。
◦ 常量区通常是只读的,防止程序在运行时修改常量。
◦ 常量区的内存分配在程序启动时完成,在程序结束时释放。
• 示例:
const char* str = "Hello, World!";
|
总结:
• 栈区:用于局部变量和函数调用,自动管理,速度快,大小有限。
• 堆区:用于动态内存分配,手动管理,速度慢,大小较大。
• 全局区:用于全局变量和静态变量,生命周期贯穿整个程序。
• 代码区:用于存储程序的二进制代码,只读。
• 常量区:用于存储字符串常量和全局常量,只读。
类和对象
链式编程
链式编程是一种编程风格,它允许你将多个函数调用链接在一起,形成一个连续的表达式。这种风格可以使代码更加简洁和易读。
需要注意的是,为了实现链式编程,函数需要返回一个引用(&)而不是值传递(即新建一个对象,将*this复制到新对象,然后返回)。
例如,下面是一个简单的链式编程示例:
#include <iostream> #include <vector> #include <algorithm> using namespace std;
class circle { private: static void info1() { cout << "private visit!" << endl; }
public: double r; static constexpr double pi = 3.1415926; circle(double _r) : r(_r) {};
~circle() { cout << "byebye" << endl; }
double calc() { return this->pi * r; }
static void info() { cout << "Im circle!" << endl; info1(); }
circle &addCircle(circle to_add) { this->r += to_add.r; return *this; } };
int main() {
circle mycicle(10); circle newcircle(10); cout << mycicle.calc() << endl;
mycicle.info(); circle ans = mycicle.addCircle(newcircle).addCircle(newcircle).addCircle(newcircle); cout << ans.r << " " << mycicle.r << endl; return 0; }
|
如果返回的是新建对象,那么每次调用都会新建一个对象,导致内存浪费。当然,如果业务正好需要新建对象,那么返回新建对象也是可以的。
circle addCircle(circle to_add) cout << ans.r << " " << mycicle.r << endl;
circle& addCircle(circle to_add) cout << ans.r << " " << mycicle.r << endl;
|
空类是否占用内存?
在C++中,空类的大小为1字节。这是因为空类没有成员变量,但是为了保持内存地址的唯一性,编译器会为空类分配一个字节的空间。这个字节被称为“空字节”,它并不存储任何有用的数据,只是为了防止两个空类的内存地址相同。
#include <iostream> #include <vector> #include <algorithm> using namespace std;
class Empty { };
int main() { Empty e; cout << sizeof(e) << endl; return 0; }
|
最后更新时间: