09-内存管理

文章详细比较了C++中的new,delete,malloc以及free操作,强调了new的构造函数初始化和析构函数清理功能,介绍了内存池和内存泄漏的概念,以及C++如何通过构造函数、析构函数和模板来改进C语言的问题。
摘要由CSDN通过智能技术生成

1.为什么C语言已经有malloc/free,C++也可以用,但是还需要new/delete.

1.针对内置类型用new还是malloc都是一样的
2.针对自定义类型,new还要调用构造函数完成初始化,delete还要调用析构函数完成清理
结论:C++中建议使用new/delete

//C
struct ListNode
{
	int _val;
	struct ListNode* _next;
	struct ListNode* _prev;
};

typedef struct ListNode ListNode;
ListNode* BuyListNode(int val)
{
	 ListNode* node_c = (ListNode*)malloc(sizeof( ListNode));
	 node_c->_val = 1;
	 node_c->_prev = NULL;
	 node_c->_next = NULL;
	 return node_c;
}
void DeatoryListNode(ListNode* node)
{

}
int main()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;

	ListNode* node1 = BuyListNode(1);
	ListNode* node2 = BuyListNode(2);
	ListNode* node3 = BuyListNode(3);
	return 0;
}

C++
struct ListNode_CPP
{
	int _val;
	struct ListNode_CPP* _next;//兼容C strruct的用法
	ListNode_CPP* _prev;	   //在CPP中,struct已经可以认为是类
	ListNode_CPP(int val = 0)
		:_val(val)
		, _next(nullptr)
		, _prev(nullptr)
	{
		cout << "ListNode_CPP(int val = 0)" << endl;
	}
	~ListNode_CPP()
	{
		cout << "~ListNode_CPP()" << endl;
	}
};
int main()
{
	ListNode_CPP* node4 = new ListNode_CPP;
	ListNode_CPP* node5 = new ListNode_CPP(5);
 
	 delete node4;
	 delete node5;
	return 0;
}
void f(int n)
{
	//Sum* p = new Sum[10];
}
int main()
{
	ListNode_CPP a[10];//调有10次拷贝构造
	ListNode_CPP* p = new ListNode_CPP[10];

	delete[] p;
	return 0;
}

 2.operator new和malloc的区别:他们使用方式都一样,处理错误的方式不一样,operator new 失败抛异常。

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};

int main()
{
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A;
	A* p3 = (A*)operator new(sizeof(A));

	//operator new和malloc的区别
	//他们使用方式都一样,处理错误的方式不一样
	size_t size = 1;
	void* p4 = malloc(size*1024*1024*1024*2);
	cout << p4 << endl;//失败返回0
	free(p4);

	try
	{
		void* p5 = malloc(size * 1024 * 1024 * 1024 * 2);
		cout << p5 << endl;//失败抛异常(面向对象处理错误的方式)
		//operator delete(p5);
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	
	return 0;
}

 3.malloc,operator new,new,free,operator free,delete 的区别。

 malloc
 operator new//==>malloc+失败抛异常实现
 new          //==>operator+构造函数
 new比起malloc不一样的地方:1.调用构造函数初始化 2.失败了抛异常
 delete比起free不一样的地方:1.调用析构函数清理  

 operator free和free没区别,因为释放空间失败直接终止进程,是因为要跟operator new成对出现

 4.内存池:

struct ListNode
{
	ListNode* _next;
	ListNode* _prev;
	int _data;

	void* operator new(size_t n)
	{
		void* p = nullptr;
		p = allocator<ListNode>().allocate(1);//内存池
		cout << "memory pool allocate" << endl;
		return p;
	}
	void operator delete(void* p)
	{
		allocator<ListNode>().deallocate((ListNode*)p,1);//内存池
		cout << "memory pool deallocate" << endl;
	}
};

class List
{
public:
	List()
	{
		_head = new ListNode;//全局operator new+构造函数
		_head->next = _head;
		_head->prev = _head;
	}
	~List()
	{
		ListNode* cur = _head->next;
		while (cur != _head)
		{
			ListNode* next = cur->_next;
			delete cur;
			cur = next;
		}
		delete _head;
		_head = nullptr;
	}
private:
	 struct ListNode* _head;
};
int main()
{
	List l;
	return 0;
}

 5.对已经存在的一块空间调用构造函数初始化。定位new/replacement new。new(对象)(空间的指针类型)(参数)。

class A
{
public:
	A(int a=0)
		:_a(a)
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p1 = new A;
	delete p1;

	//想模拟上面的行为
	//显示调用了A的构造函数和析构函数
	A* p2 =(A*) operator new(sizeof(A));
	//对已经存在的一块空间调用构造函数初始化。定位new/replacement new
	new(p2)A(10);//new(对象)(空间的指针类型)(参数)

	p2->~A();
	operator delete(p2);
	return 0;
}

6.内存泄漏:

int main()
{
	//1G
	char* p = new char[1024 * 1024 * 1024];

	//内存泄漏:p指向的空间不需要了,忘记或其他原因没有释放p指向的空间,就内存泄漏
	//内存泄漏危害:长期运行的程序(游戏服务),出现内存泄漏危害很大,或者设备的内存本身很小也有危害
	return 0;
}

 7.泛型编程,模板->写跟类型无关的代码,函数模板

函数重载有时太过于繁琐:如:

void Swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}
void Swap(double& left, double& right)
{
	double tmp = left;
	left = right;
	right = tmp;
}
void Swap(char& left, char& right)
{
	char tmp = left;
	left = right;
	right = tmp;
}
int main()
{
	int a = 0, b = 1;
	Swap(a, b);
	double c = 1.1, d = 2.2;
	Swap(c, d);
	return 0;
}

 所以可以用函数模板:

//泛型编程
//模板->写跟类型无关的代码
//函数模板
template<class T>
template<typename T>//模板参数-》类型
void Swap(T& x1, T& x2)
{
	T x = x1;
	x1 = x2;
	x2 = x;
}
//下面调用的是否是同一个函数?
//不是
//这里我们不能调用模板,调用的是函数模板实例化生成的对应类型的函数
int main()
{
	int a = 0, b = 1;
	Swap(a, b);
	double c = 1.1, d = 2.2;
	Swap(c, d);
	char e = 'a', f = 'b';
	Swap(e, f);
	return 0;
}

 8.C语言的一些问题,C++可以通过构造,析构,模板解决:

//C语言如何实现一个栈
typedef int STDateType;
struct Stack
{
	int* _a;
	int size;
	int _capacity;
};

typedef struct Stack Stack;
void StackInit(Stack* ps)
{}
void StackDeatory(Stack* ps)
{}
void StackPush(Stack* ps,STDateType x)
{}
void StackPop(Stack* ps)
{}

template<class T>
class Stack_CPP
{
public:
	Stack_CPP()
	{

	}
	~Stack_CPP()
	{

	}
	void Push(T x)
	{}

private:
	T* _a;
	int _size;
	int _capacity;
};
int main()
{   //C语言的问题													C++如何解决
	//1.忘记初始化和销毁											->构造函数+析构函数
	//2.没有封装,谁都可以修改结构体的数据							->类+访问限定符
	//3.如果想同时定义两个栈,一个栈存int,一个栈存double,做不到		->模板
	Stack st;
	StackPush(&st, 1);
	StackPush(&st, 2);
	StackPush(&st, 3);
	StackPush(&st, 4);
	//非法修改
	st._capacity = 0;
	StackDeatory(&st);

	Stack_CPP<int> st_cpp_int;
	st_cpp_int.Push(1);//实际上我也有两个参数,有一个是隐含的this指针
	st_cpp_int.Push(2);
	st_cpp_int.Push(3);
	st_cpp_int.Push(4);

	Stack_CPP<double> st_cpp_double;
	st_cpp_double.Push(1.1);
	st_cpp_double.Push(2.2);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值