在C/C++程序中,内存分布通常分为以下几个主要部分:
这种内存布局有助于程序的高效运行和内存管理。
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
在 C 语言中,动态内存管理是通过几个标准库函数来实现的,这些函数主要包括 malloc
、calloc
、realloc
和 free
。这些函数都在 <stdlib.h>
头文件中定义。以下是它们的主要功能和用法:
malloc
函数:
void* malloc(size_t size);
NULL
。int *ptr = (int*)malloc(10 * sizeof(int));
if (ptr == NULL) {
// 处理内存分配失败
}
calloc
函数:
void* calloc(size_t num, size_t size);
NULL
。int *ptr = (int*)calloc(10, sizeof(int));
if (ptr == NULL) {
// 处理内存分配失败
}
realloc
函数:
void* realloc(void* ptr, size_t new_size);
NULL
。ptr = (int*)realloc(ptr, 20 * sizeof(int));
if (ptr == NULL) {
// 处理内存分配失败
}
free
函数:
malloc
、calloc
或 realloc
分配的内存。void free(void* ptr);
free(ptr);
ptr = NULL; // 避免悬空指针
在 C++ 中,new
和 delete
操作符用于动态内存管理,特别是内置类型的内存分配和释放。以下是它们的基本用法和注意事项:
new
操作符分配单个内置类型的内存:
int* ptr = new int; // 分配一个 int 类型的内存
*ptr = 10; // 初始化
分配并初始化单个内置类型的内存:
int* ptr = new int(10); // 分配并初始化为 10
分配数组内置类型的内存:
int* arr = new int[10]; // 分配一个包含 10 个 int 类型元素的数组
delete
操作符释放单个内置类型的内存:
delete ptr; // 释放单个 int 类型的内存
释放数组内置类型的内存:
delete[] arr; // 释放数组内存
异常处理:new
操作符在内存分配失败时会抛出 std::bad_alloc
异常,而 malloc
则返回 NULL
。因此,使用 new
时可以通过 try-catch
块来处理异常。
try {
int* ptr = new int[1000000000]; // 可能会失败
} catch (std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
}
避免内存泄漏:确保每个 new
对应一个 delete
,每个 new[]
对应一个 delete[]
,以避免内存泄漏。
初始化:使用 new
分配的内存未初始化(除非显式初始化),而 new int(10)
这样的语法可以直接初始化内存。
在 C++ 中,new
和 delete
操作符不仅可以用于内置类型,还可以用于自定义类型(类)。以下是如何使用 new
和 delete
来管理自定义类型的内存:
new
操作符分配单个自定义类型对象的内存:
class MyClass {
public:
MyClass(int value) : data(value) {}
~MyClass() {}
private:
int data;
};
MyClass* obj = new MyClass(10); // 调用构造函数
分配数组自定义类型对象的内存:
MyClass* objArray = new MyClass[3]; // 调用默认构造函数
delete
操作符释放单个自定义类型对象的内存:
delete obj; // 调用析构函数
释放数组自定义类型对象的内存:
delete[] objArray; // 调用每个对象的析构函数
new
分配内存时,会自动调用构造函数进行初始化;使用 delete
释放内存时,会自动调用析构函数进行清理。new[]
分配数组时,必须使用 delete[]
释放内存,以确保每个对象的析构函数都被正确调用。new
操作符在分配失败时会抛出 std::bad_alloc
异常,可以使用 try-catch
块来处理。#include <iostream>
class MyClass {
public:
MyClass(int value = 0) : data(value) {
std::cout << "Constructor called with value: " << data << std::endl;
}
~MyClass() {
std::cout << "Destructor called for value: " << data << std::endl;
}
private:
int data;
};
int main() {
// 分配单个对象
MyClass* obj = new MyClass(10);
delete obj;
// 分配对象数组
MyClass* objArray = new MyClass[3];
delete[] objArray;
return 0;
}
在 C++ 中,new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
operator new
函数基本用法:
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void*__CRTDECLoperatornew(size_tsize) _THROW1(_STDbad_alloc)
{// try to allocate size bytes
void*p;
while ((p=malloc(size)) ==0)
if (_callnewh(size) ==0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
staticconststd::bad_allocnomem;
_RAISE(nomem);
}
return (p);
}
size
字节的内存,并返回一个指向这块内存的指针。std::bad_alloc
异常。示例:
void* ptr = operator new(sizeof(int) * 10); // 分配 10 个 int 的内存
重载:
operator new
以自定义内存分配行为。例如: void* MyClass::operator new(size_t size) {
void* p = ::operator new(size);
// 自定义初始化或日志记录
return p;
}
operator delete
函数基本用法:
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
operator new
分配的内存。pUserData
是指向要释放的内存的指针。示例:
operator delete(ptr); // 释放内存
重载:
operator delete
以自定义内存释放行为。例如: void MyClass::operator delete(void* ptr) {
// 自定义清理或日志记录
::operator delete(ptr);
}
operator new[]
和 operator delete[]
void* operator new;
void operator delete;
operator new
和 operator delete
类似,但用于数组。#include <iostream>
#include <new> // 包含 operator new 和 operator delete 的声明
class MyClass {
public:
MyClass() { std::cout << "Constructor called\n"; }
~MyClass() { std::cout << "Destructor called\n"; }
void* operator new(size_t size) {
std::cout << "Custom operator new\n";
return ::operator new(size);
}
void operator delete(void* ptr) {
std::cout << "Custom operator delete\n";
::operator delete(ptr);
}
};
int main() {
MyClass* obj = new MyClass(); // 调用自定义的 operator new
delete obj; // 调用自定义的 operator delete
return 0;
}
在 C++ 中,new
和 delete
操作符用于动态内存管理,特别是自定义类型(类)的内存分配和释放。它们的实现原理与内置类型类似,但涉及构造函数和析构函数的调用。以下是它们的实现原理和示例代码:
new
操作符的实现原理内存分配:
new
操作符在底层调用operator new
函数来分配内存。operator new
通常使用malloc
来分配内存。- 如果内存分配失败,
operator new
会抛出std::bad_alloc
异常。
对象初始化:
- 对于自定义类型,
new
操作符会调用构造函数来初始化对象。- 这一步是
new
操作符与malloc
函数的主要区别之一。
delete
操作符的实现原理对象清理:
- 对于自定义类型,
delete
操作符会调用析构函数来清理对象。- 这一步在释放内存之前进行,以确保对象的资源被正确释放。
内存释放:
delete
操作符在底层调用operator delete
函数来释放内存。operator delete
通常使用free
来释放内存。
以下是一个自定义类 MyClass
,并展示了 new
和 delete
的使用:
#include <iostream>
#include <new> // 包含 operator new 和 operator delete 的声明
class MyClass {
public:
MyClass(int value) : data(value) {
std::cout << "Constructor called with value: " << data << std::endl;
}
~MyClass() {
std::cout << "Destructor called for value: " << data << std::endl;
}
private:
int data;
};
int main() {
// 使用 new 分配单个对象
MyClass* obj = new MyClass(10); // 调用构造函数
delete obj; // 调用析构函数并释放内存
// 使用 new 分配对象数组
MyClass* objArray = new MyClass[3]; // 调用默认构造函数
delete[] objArray; // 调用析构函数并释放数组内存
return 0;
}
operator new
和 operator delete
:可以通过重载这些操作符来自定义内存分配和释放行为。在 C++ 中,定位 new
表达式(placement new)是一种特殊的内存分配方式,它允许在已经分配好的内存上构造对象。通常情况下,new
操作符会在堆上分配内存并调用构造函数来初始化对象,而定位 new
允许我们在已有的内存空间上构造对象。
void* operator new(size_t size, void* ptr) noexcept;
size
:要分配的内存大小,通常是对象的大小。ptr
:指向已分配好的内存空间的指针。以下是一个使用定位 new
的示例:
#include <iostream>
#include <new> // 包含 placement new 的声明
class MyClass {
public:
MyClass(int value) : data(value) {
std::cout << "Constructor called with value: " << data << std::endl;
}
~MyClass() {
std::cout << "Destructor called for value: " << data << std::endl;
}
private:
int data;
};
int main() {
// 预先分配内存
char buffer[sizeof(MyClass)];
// 使用定位 new 在已有内存上构造对象
MyClass* obj = new (buffer) MyClass(42);
// 调用对象的方法
obj->~MyClass(); // 显式调用析构函数
return 0;
}
- 手动调用析构函数:使用定位
new
构造的对象需要手动调用析构函数,因为delete
不会释放由定位new
分配的内存。- 内存管理:确保
ptr
指向的内存足够大且未被其他对象占用,否则可能导致未定义行为。- 内存对齐:确保
ptr
指向的内存地址满足对象的对齐要求。
定位 new 常用于内存池或固定内存区域中管理对象,以提高性能和内存管理的效率
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- bangwoyixia.com 版权所有 湘ICP备2023022004号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务