目录
new
1.什么是new?
C++中,new是一个运算符,用于动态分配内存,返回一个指向分配内存的指针,通常和delete运算符一起使用,用于在堆上分配和释放内存。
同C语言的malloc()不同,new通过调用构造函数去初始化对象,当使用delete()释放内存时,会调用对象的析构函数,而对象的生命周期从构造函数完成时开始,到析构函数完成时结束。
2.new的基本用法
a. 分配单个对象
new(n) 分配一个大小的内存空间,以括号中的值来初始化这个变量
#include<bits/stdc++.h>
using namespace std;
int main(){
int *a=new int(5); //动态分配一个int类型的内存,并初始化为5
cout<<sizeof(a)<<" "<<a<<endl; //输出指针a的大小和地址
cout<<sizeof(*a)<<" "<<*a<<endl; //输出指针a指向的对象的大小和值
delete a;//释放动态分配的内存,释放单个对象
return 0;
}
b.分配数组
new[ ] 分配n个大小的内存空间,用默认构造函数初始化这些变量
#include<bits/stdc++.h>
using namespace std;
int main(){
int *a=new int[5];
for(int i=1;i<=5;++i){
a[i]=i;
}
for(int i=1;i<=5;++i){
cout<<a[i]<<" ";
}
delete[] a;//释放对象数组
return 0;
}
注意:
- 使用new动态分配的内存必须使用delete或delete[ ]释放
- 当使用new运算符定义一个多维数组或数组对象时,它产生一个指向第一个元素的指针,返回的类型保持除了最左边维数外的所有维数。
- int (*a)[3][5] = new int[5][3][10]; 返回的是一个指向二维数组int[3][10]这种类型的指针int (*)[3][5]
c.带参数的构造函数
在C++中,使用new创建对象时,可以通过构造函数传递参数来初始化对象。
#include<bits/stdc++.h>
using namespace std;
class MyClass{
private:
int value;
public:
//带参数的构造函数,使用初始化列表
MyClass(int v):value(v){
cout<<"参数构造value:"<<value<<endl;
}
};
int main(){
MyClass* a=new MyClass(5);
delete a;
return 0;
}
3.new的高级特性
a.自定义内存分配器
通过重载全局或类级别的poerator new来实现自定义分配逻辑
#include <iostream>
#include <cstdlib>
#include <new> // 包含 std::bad_alloc
// 自定义全局 new 操作符
void* operator new(size_t size) {
std::cout << "Custom new called for size: " << size << std::endl;
void* ptr = std::malloc(size);
if (!ptr) {
throw std::bad_alloc(); // 如果分配失败,抛出异常
}
return ptr;
}
// 自定义全局 delete 操作符
void operator delete(void* ptr) noexcept {
std::cout << "Custom delete called" << std::endl;
std::free(ptr);
}
b.抛出异常处理
当new无法为请求分配足够的内存时,默认情况下会抛出一个std::bad_alloc异常
try {
// 尝试分配一个非常大的内存块
int* largeArray = new int[1000000000000];
std::cout << "Memory allocation succeeded" << std::endl;
delete[] largeArray; // 释放内存
} catch (const std::bad_alloc& e) {
std::cerr << "Memory allocation failed: " << e.what() << std::endl;
}
c.无抛出版本
MyClass* obj = new (std::nothrow) MyClass(10);
if (obj == nullptr) {
std::cerr << "Memory allocation failed" << std::endl;
}
4.new的使用注意事项
a. new和delete总是成对出现:使用了new分配内存之后,就应该考虑如何以及何时使用delete去释放它,避免内存泄漏
b. 优先考虑智能指针:C++标准库提供了几种智能指针类型,最常用的就是std::unique_ptr 和 std::shared_ptr。智能指针可以有效避免内存泄漏和悬空指针的问题,智能指针通过RAII机制,在对象生命周期结束时自动释放资源。
c. 避免频繁使用动态分配:动态分配虽然灵活,但效率较低且容易导致内存碎片化,尽可能将对象放到栈上。
malloc
1.什么是malloc?
头文件为#include的 C库函数void *malloc(size_t size)分配所需空间,并返回一个指向它的指针。
2.函数声明
void *malloc(size_t size)
- size:内存块大小,以字节为单位
- 返回值:返回一个指针,指向已分配大小的内存块;如果分配失败则返回空指针NULL
- 释放:当内存不在使用时,用使用free()函数释放
3.实例用法
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
//初始化为hello
char* str = (char*)malloc(6);
//(char*)用于显示转换malloc返回的void*类型的指针
strcpy(str, "hello");
printf("str:%s;str的地址:%u\n", str,str);
//重新分配
str = (char*)realloc(str,15);
strcpy(str, "hello,world");
printf("str:%s;str的地址:%u\n", str, str);
return(0);
}
代码结果展示:
str:hello;str的地址:2048660064
str:hello,world;str的地址:2048659424
new和malloc的区别
- new的返回值不需要强制转换,malloc的返回值需要强制转换
- new是运算符可以重载,malloc是库函数,不能重载
- new不需要传入想要申请的具体字节个数,malloc需要传入想要申请的具体字节个数
- new申请失败会抛出异常,malloc申请失败会返回空
- 如果给一个类分配堆区内存new会先调用malloc分配内存,然后再调用构造函数给成员变量赋值
- new申请的堆区内存需要delete释放,delete先调用析构函数再调用free(free也是C语言库函数和malloc是配套的)