文章目录
- 20. 指针 vs 引用
- 21. new vs malloc
20. 指针 vs 引用
- 指针是实体,占用内存空间,逻辑上独立;引用是别名,与变量共享内存空间,逻辑上不独立。
- 指针定义时可以不初始化;引用定义时必须初始化。
- 指针的值可以变,即可以指向别的内存地址;引用不变的。
- 指针可以为nullptr;引用不能为空。
- sizeof(指针)计算指针大小,由于指针保存的是内存地址,所以无论什么类型的指针,在32位程序里占4B,在64位程序里占8B;而sizeof(引用)计算引用对象的大小。
- 指针自增用于地址偏移,运算结果取决于指针类型,因为当指针保存的是数组首地址时,为了能够利用指针自增后访问到数组下一成员,所以加的是类型长度,而非1,如下图;引用自增是引用对象自增。
- 指针取出数据内容时需要解引用;引用不需要。
- 有二级指针;没有二级引用。
- 【注意】 如果返回动态分配的内存,必须使用指针,使用引用会内存泄漏,如下图。
分析1:使用CRT库检测内存泄漏,4B,因为不能删除引用指向的内存地址,即使用 delete& ref 会触发中断。
分析2:相比之下,使用指针返回动态分配的内存,可以在不需要时使用 delete释放内存,从而避免内存泄漏。
21. new vs malloc
- new是C++运算符;malloc是C的库函数。
- new返回指定类型指针;malloc返回void*指针,需要强制类型转换。
- new自动计算需分配的空间;malloc需要指定分配空间的大小。
- new可以被重载;malloc不能,代码如下。
#include<iostream>
using namespace std;
// 重载 new 操作符
void* operator new(size_t size)
{
cout << "Custom new: Allocating " << size << " bytes" << endl;
void* ptr = std::malloc(size);
if (!ptr) {
throw std::bad_alloc(); // 内存分配失败时抛出异常
}
return ptr;
}
// 重载 delete 操作符
void operator delete(void* ptr) noexcept {
cout << "Custom delete: Freeing memory" << endl;
free(ptr);
}
int main()
{
int* arr = new int(4);
delete arr;
return 0;
}
程序运行结果,如下图。
- 代码如下,进行以下分析。
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include<iostream>
using namespace std;
class MyClass {
private:
int* value;
public:
MyClass(int v) : value(new int(v)) {
printf("%s\n", "Constructor class");
}
~MyClass()
{
delete value;
printf("%s\n", "Delete class");
}
};
int main()
{
MyClass* obj1 = new MyClass(42);
MyClass* obj2 = (MyClass*)malloc(sizeof(MyClass));
new(obj2) MyClass(44);
delete obj1;
free(obj2);
_CrtDumpMemoryLeaks();
return 0;
}
-
new会调用构造函数;malloc不会,即malloc只是分配内存空间,需要在其他地方初始化,如下图。
分析1:MyClass类大小,看它的数据成员大小,即4B。使用new时,先申请4B内存空间,然后调用构造函数进行初始化。
分析2:使用malloc时,只申请4B内存空间。然后使用new(obj2) MyClass(44);显示调用构造函数,进行初始化。
分析3:new的内部实现,会调用malloc分配内存空间。 -
【注意】 new使用delete释放内存空间,在释放前会调用析构函数;malloc使用free释放内存空间,由于不会调用析构函数,会造成内存泄漏,如下图。
分析1:使用delete时,先调用析构函数释放对象内存空间,再释放指针内存空间。
分析2:使用free时,只释放指针内存空间,由于对象内存空间无法释放,造成内存泄漏。