作者简介:专注于C/C++高性能程序设计和开发,理论与代码实践结合,让世界没有难学的技术。包括C/C++、Linux、MySQL、Redis、TCP/IP、协程、网络编程等。
️ CSDN实力新星,社区专家博主
专栏介绍:从零到c++精通的学习之路。内容包括C++基础编程、中级编程、高级编程;掌握各个知识点。
专栏地址:C++从零开始到精通
博客主页:https://blog.csdn.net/Long_xu
上一篇:【019】C++的指针与函数
C++中的动态内存分配是在程序运行时根据需要进行内存空间的分配和释放,与静态内存分配相比,具有更大的灵活性和适应性。动态内存分配可以通过new
和delete
或者malloc()
和free()
等函数实现。
动态内存分配通常用于以下情况:
如果在动态分配内存后忘记了释放它,则会导致内存泄漏。为避免内存泄漏,可以使用智能指针或手动管理内存的方式来释放动态分配的内存。
(1)静态分配:
(2)动态分配:
(3)堆和栈的区别:
在 C++ 中,动态内存的申请和释放需要使用关键字 new
和 delete
。
new
是一个操作符,可以用来在堆上分配一段内存,并返回该内存块的地址。它的语法为:
new 数据类型;
例如:
int* p = new int; // 在堆上分配一个 int 类型的空间
double* q = new double; // 在堆上分配一个 double 类型的空间
使用了 new
操作符在堆上分别申请了一个 int
类型和一个 double
类型的空间,并将其地址赋值给指针变量 p
和 q
。
如果要同时初始化所申请的内存块,可以使用如下形式:
数据类型* 指针名 = new 数据类型(初值);
例如:
int* p = new int(10); // 在堆上分配一个 int 类型的空间,并初始化为 10
char* q = new char('A'); // 在堆上分配一个 char 类型的空间,并初始化为 'A'
使用 new
分配了内存后,在不再需要这些内存时应该手动释放。释放所申请的内存可以使用关键字 delete
。它有两种用法:一种是只删除单个对象的内存块,另一种是删除数组的内存块。
delete
后面加上指向该对象的指针即可:delete 指针名;
例如:
int* p = new int(10); // 在堆上分配一个 int 类型的空间,并初始化为 10
delete p; // 释放申请的空间
注意:使用完 new
分配的内存后,一定要记得使用 delete
将其释放掉,否则会造成内存泄漏。
new
来分配数组,则需要使用带有方括号 [] 的 delete
来释放所申请的内存。语法如下:delete[] 数组指针;
例如:
int* p = new int[5]; // 在堆上分配一个长度为 5 的 int 数组
delete[] p; // 释放申请的空间
注意:在使用带有方括号 [] 的 new
分配数组时,必须使用带有方括号 [] 的 delete
进行释放,否则会导致未定义行为。
示例:
#include
using namespace std;
int main() {
int* p1 = new int;
*p1 = 10;
cout << "p1: " << *p1 << endl;
double* p2 = new double(3.14);
cout << "p2: " << *p2 << endl;
int* arr = new int[5];
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
cout << "arr[" << i << "]: " << arr[i] << endl;
}
delete[] arr;
delete p1;
delete p2;
return 0;
}
输出结果:
p1: 10
p2: 3.14
arr[0]: 1
arr[1]: 2
arr[2]: 3
arr[3]: 4
arr[4]: 5
new负责申请空间,delete负责释放空间。
#include
using namespace std;
int main()
{
int *x=new int;//从堆区申请int类型大小的空间
x=100;
cout<<"*x = "<<*x<<endl;
int *x2=new int(1000);//从堆区申请int类型大小的空间,并初始化
cout<<"*x2 = "<<*x2<<endl;
delete x2;//释放空间
delete x;//释放空间
return 0;
}
new与[]结合表示申请数组空间,delete释放的时候也需要[]。
#include
using namespace std;
int main()
{
int *arr = new int[5]{ 1,2,3,4,5 };
for (int i = 0; i < 5; i++)
{
cout << arr[i] << " ";
}
cout << endl;
delete[] arr;
return 0;
}
输出:
1 2 3 4 5
C++ 中可以通过重载 new
和 delete
操作符来实现自定义的内存管理。重载后的操作符可以用于在不同情况下分配和释放内存。
operator new
函数来重载 new
操作符。它是一个静态成员函数,其原型如下:void* operator new (size_t size);
其中,参数 size
表示要申请的内存块大小,返回值为指向申请到的内存块的指针。以下是一个简单的例子:
#include
using namespace std;
class MyClass {
public:
void* operator new (size_t size) {
cout << "Customized allocation of " << size << " bytes memory." << endl;
return malloc(size);
}
};
int main() {
MyClass* p = new MyClass();
delete p;
return 0;
}
输出结果:
Customized allocation of 1 bytes memory.
上述代码中,定义了一个名为 MyClass
的类,并在其中重载了 new
操作符。在这个例子中,没有真正地改变分配内存的方式,而是只是增加了一些输出信息以便观察调用情况。
operator delete
函数来重载 delete
操作符。它也是一个静态成员函数,其原型如下:void operator delete (void* ptr);
其中,参数 ptr
表示要释放的内存块地址。
简单的例子:
#include
using namespace std;
class MyClass {
public:
void* operator new (size_t size) {
cout << "Customized allocation of " << size << " bytes memory." << endl;
return malloc(size);
}
void operator delete (void* ptr) {
cout << "Customized deallocation." << endl;
free(ptr);
}
};
int main() {
MyClass* p = new MyClass();
delete p;
return 0;
}
输出结果:
Customized allocation of 1 bytes memory.
Customized deallocation.
上述代码中,不仅重载了 new
操作符,还重载了 delete
操作符。在这个例子中,通过使用 free()
函数来释放内存。
需要注意的是,在重载 delete
操作符时,必须与重载 new
操作符配对使用。也就是说,如果想自定义分配方式,则需要同时自定义释放方式。
上述是在类中重载,也可以在非类中重载new
和delete
操作符实现自定义的内存分配和释放方式。例如:
void* operator new(size_t size) {
void* p = malloc(size);
if(!p) throw std::bad_alloc();
return p;
}
void operator delete(void* p) noexcept {
free(p);
}
以上代码实现了一个自定义的new
和delete
操作符,其中使用了标准库中的异常类std::bad_alloc()
来处理内存申请失败的情况,并使用了C语言中的malloc()
和free()
函数来进行内存分配和释放。
需要注意的是,在重载操作符时需要保证与标准库中的操作符具有相同的语义,否则可能会导致意外行为或程序崩溃。
动态分配内存的优点:
灵活性:动态分配内存允许程序根据需要在运行时分配和释放内存,从而可以适应不同的数据量和操作需求。
节省空间:动态分配内存只会占用实际需要的空间,避免了静态分配过多空间造成的浪费。
提高效率:合理利用动态内存分配可以提高程序的效率,尤其是对于大型数据结构或需要多次重复调用某个函数的情况。
可扩展性:由于动态内存分配可以根据需求增加或减少内存空间,因此程序具有很好的可扩展性。
动态分配内存的缺点:
内存泄漏:如果不正确地使用和管理动态分配的内存,就可能导致内存泄漏问题,这会严重影响程序运行效率和稳定性。
复杂性:相比静态内存分配,在动态内存分配中需要进行更多复杂的操作,如申请、释放、回收等。同时也需要考虑到指针、数组等相关问题。
代码容易出错:由于涉及到指针操作和较为复杂的编程技巧,因此代码容易出现错误,增加了程序的调试难度。
程序安全性:由于动态内存分配可以被黑客用来进行缓冲区溢出等攻击,因此需要谨慎使用,并做好相应的安全措施。
C++中的动态内存分配是在程序运行时根据需要进行内存空间的分配和释放,与静态内存分配相比,具有更大的灵活性和适应性。动态内存分配可以通过new
和delete
或者malloc()
和free()
等函数实现。
new
和 delete
。使用new
关键字可以在堆上分配指定类型大小的内存空间,并返回指向该空间起始位置的指针。例如:
int *p = new int; // 分配一个int类型大小的空间
*p = 10; // 对该空间赋值
delete p; // 释放该空间
使用new[]
关键字可以在堆上分配指定数量、类型大小相同的连续内存空间,并返回指向该空间起始位置的指针。例如:
int size = 10;
int *arr = new int[size]; // 分配一个包含10个int类型元素的数组
for(int i = 0; i < size; i++) {
arr[i] = i;
}
delete[] arr; // 释放该数组
需要注意的是,使用new
和delete
时需要保证分配和释放的内存大小和类型一致,否则会导致内存泄漏或程序崩溃。
内存泄漏。如果在动态分配内存后忘记了释放它,则会导致内存泄漏。为避免内存泄漏,可以使用智能指针或手动管理内存的方式来释放动态分配的内存。
其他注意事项: