Loading

1.控制内存分配的new和delete等

C++内存管理的架构

C++ memory primitives

memory primitives 测试

#include <cstdlib>
#include <iostream>
#include "memory_primitives_test.h"
#include <vector>
#include <memory>
namespace memory_primitives_test {
	void memory_primitives_test_function() {

		std::cout << "malloc test start" << std::endl;
		void *p1 = malloc(512);  //512bytes
		free(p1);
		std::cout << "malloc test is over" << std::endl;
		//2.new的测试
		std::cout << "new test start" << std::endl;
		std::vector<int>* p2 = new std::vector<int>;
		delete p2;
		std::cout << "new test is over" << std::endl;

		std::cout << "operator new test start" << std::endl;
		void *p3 = ::operator new (512); //直接执行全局作用域中的operator new
		::operator delete(p3);
		std::cout << "operator new test is over" << std::endl;

		//测试allocators,其接口虽然有标准规格,但是不同的厂商实现了不同的接口	
		//一般不会通过分配器直接拿内存
#ifdef _MSC_VER
		std::cout << "allocator test start" << std::endl;
		int *p4 = std::allocator<int>().allocate(3, (int*)0); //分配3个ints
		std::allocator<int>().deallocate(p4, 3);
		std::cout << "allocator test is over" << std::endl;
#endif

#ifdef __BORLANDC__
		int *p4 = allocator<int>().allocate(5);
		allocator<int>().deallocate(p4, 5);
#endif

#ifdef __GNUC__
		void *p4 = alloc::allocate(512);
		alloc::deallocate(p4, 512);
#endif

	}

}


new在编译器中的执行过程

Complex *pc = new Complex(1,2);

被编译器解释成以下代码:并且只有编译器才能做到如下所示的执行过程:

Complex *pc;
try {
    void *mem = operator new(sizeof(Complex));
    pc = static_cast<Complex*>(mem);
    pc->Complex::Complex(1,2);
}
catch (std::bad_alloc) {
    //若失败,就不执行构造函数了
    
}

delete在编译器中的执行过程

delete pc;

被编译器解释成以下代码:并且只有编译器才能做到如下所示的执行过程:

pc->~Complex();  //先析构
operator delete(pc);  //再释放内存

其中operator delete又会调用free

void__cdecl opeartor delete(void *p) _THROW0() {
    //free an allocated object
    free(p);
}

array new在编译器中的执行过程

string *psa = new string[3];
delete []psa;

array new得到的是绿色的部分加上一个小的cookie(记录一些琐碎的东西,比如数组的长度等)

如上图所示,在 $ delete $时如果没有加上 $ [ ] $,回收还是正常回收的,但是析构函数只会被调用一次,即析构的可能是数组的第一个,也可能是数组的最后一个,这会造成内存泄露。

而如果是下面这个例子:

Complex* pca = new Complex[3]; //调用3次构造函数

delete [] pca; //调用三次析构函数


其中并没有指针指向析构函数,所以它的析构函数根本没有用,在析构时是可以不用加 $ [] $ 的,是不会造成内存泄露的,但是为了格式的统一,还是要加上[]

placement new在编译器中的执行过程

   placement new允许我们将object建立于allocated memory中。
没有所谓的placement delete,因为placement new根本没有分配memory,

		char *buf = new char[sizeof(Complex) * 3];
		Complex *pc = new(buf)Complex(1,2);

		delete [] buf;

	//被编译器转为
		Complex *pc;
		try {
			void *mem = operator new(sizeof(Complex), buf);
			pc = static_cast<Complex*>(mem);
			pc->Complex::Complex(1, 2);
		}
		catch (std::bad_alloc)
		{
			//若分配失败,则不执行constructor
		}

   所以 placemenet new或指new(p)或指::operator new(size,void*)

C++分配内存途径

C++ 应用程序分配内存的途径

C++ 容器分配内存的途径

重载new/class::operator new/::operator new

重载全局::operator new /::operator delete

//重载::operator new /::operator delete /::operator new[] /::operator delete[]
void* myAlloc(size_t size) {
	return malloc(size); //返回一个指针指向malloc的内存
}

void myFree(void *ptr) {
	return free(ptr);
}

inline void * operator new(size_t size) {
	std::cout << "global new() \n ";
	return myAlloc(size);
}

inline void operator delete(void* ptr) {
	std::cout << "global delete() \n";
	return myFree(ptr);
}

重载全局/::operator new[] /::operator delete[]

inline void* operator new[](size_t size) {
	std::cout << "global new() \n";
	return myAlloc(size);
}
inline void operator delete[](void *ptr) {
	std::cout << "global delete [] \n";
	myFree(ptr);
}

重载类内的operator new /operator delete

必须是static的

重载类内的operator new[] /operator delete[]

必须是static

定义类Foo

重载类的operator new和operator delete 以及operator new []和operator delete[],注意重载的operator new等为static的

	//重载载类内的operator new和operator delete
	class Foo {
	public:
		int _id;
		long _data;
		std::string _st;
	public:
		Foo() : _id(0) { std::cout << "default cotr. this = " << this << "   id=" << _id << std::endl; }
		Foo(int i):_id(i) { std::cout << "default cotr. this = " << this << "   id=" << _id << std::endl; }
		~Foo() { std::cout << "dtor. this= " << this << "  id= " << _id << std::endl; }

		static void *operator new(size_t size);
		static void operator delete(void* pdead, size_t size);
		static void *operator new[](size_t size);
		static void operator delete[](void*pdead, size_t size);
	};

operator new等重载实现

	//Foo内的operator new
	void *Foo::operator new(size_t size) {
		Foo* p = (Foo*)malloc(size);
		std::cout << "Foo operator new" << std::endl;;
		return p;
	}
	//Foo内的operator delete
	void Foo::operator delete(void* pdead, size_t size) {
		std::cout << "Foo opeartor delete" << std::endl;
		free(pdead);
	}
	//Foo内的operator new[]
	void *Foo::operator new[](size_t size) {
		Foo* p = (Foo*)malloc(size);
		std::cout << "Foo operator new[]" << std::endl;;
		return p;
	}
	//Foo内的operator delete[]
	void Foo::operator delete[](void* pdead, size_t size) {
		std::cout << "Foo opeartor delete[]" << std::endl;
		free(pdead);
	}

主函数测试

	std::cout << "sizeof(Foo)" << sizeof(Foo) << std::endl;
	//测试operator new和operator delete
	Foo *p = new Foo(7);
	delete p;
	//测试operator new[] 和operator delete[]
	Foo* pArray = new Foo[5];
	delete[] pArray;

测试结果

sizeof(Foo)36
Foo operator new
default cotr. this = 0063EE50   id=7
dtor. this= 0063EE50  id= 7
Foo opeartor delete
Foo operator new[]
default cotr. this = 006412CC   id=0
default cotr. this = 006412F0   id=0
default cotr. this = 00641314   id=0
default cotr. this = 00641338   id=0
default cotr. this = 0064135C   id=0
dtor. this= 0064135C  id= 0
dtor. this= 00641338  id= 0
dtor. this= 00641314  id= 0
dtor. this= 006412F0  id= 0
dtor. this= 006412CC  id= 0
Foo opeartor delete[]
请按任意键继续. . .

测试全局的operator new和operator delete

	std::cout << "sizeof(Foo)" << sizeof(Foo) << std::endl;
	//测试operator new和operator delete
	Foo *p = ::new Foo(7);
	::delete p;
	//测试operator new[] 和operator delete[]
	Foo* pArray = ::new Foo[5];
	::delete[] pArray;

全局的operator new和operator delete测试结果

sizeof(Foo)36
default cotr. this = 003EEE50   id=7
dtor. this= 003EEE50  id= 7
default cotr. this = 003F12CC   id=0
default cotr. this = 003F12F0   id=0
default cotr. this = 003F1314   id=0
default cotr. this = 003F1338   id=0
default cotr. this = 003F135C   id=0
dtor. this= 003F135C  id= 0
dtor. this= 003F1338  id= 0
dtor. this= 003F1314  id= 0
dtor. this= 003F12F0  id= 0
dtor. this= 003F12CC  id= 0
请按任意键继续. . .

发现并没有进入Foo类内的operator new和operator delete。

重载new()和delete()

我们可以重载class member operator new(),写出多个版本,前提是每个版本的声明都具有不同的参数列,且其中第一个参数必须是size_t,其余参数是以new所指定的placement arguments为初值,出现new (...)小括号内的便是所谓的placement arguments。

Foo *pf = new(300,'c')Foo;

我们也可以重载class member operator delete(),写出多个版本,但它们绝对不会被delete调用,只有当new所调用的ctor抛出exception时,才会调用这些重载的operator delete().它只可能这样被调用,主要用于未能完全创建成功的object所占用的memory.

重载new()和delete()实现


	//重载new()和delete()
	void* Foo::operator new(size_t size, void *start) {
		return start;
	}
	void* Foo::operator new(size_t size, long extra) {
		return malloc(size + extra);
	}
	void* Foo::operator new(size_t size, long extra, char init) {
		return malloc(size + extra);
	}

	//如果调用构造函数失败,才会调用如下的构造函数
	void Foo::operator delete (void*, size_t) {
		std::cout << "operator delete(void*,size_t)" << std::endl;
	}
	void Foo::operator delete(void*, void*) {
		std::cout << "operator delete(void*,void*)" << std::endl;
	}
	void Foo::operator delete(void*, long) {
		std::cout << "operator delete(void*,long)" << std::endl;
	}
	void Foo::operator delete(void*, long, char) {
		std::cout << "operator delete(void*,long,char)" << std::endl;
	}

posted @ 2020-01-13 10:15  三只猫-  阅读(230)  评论(0编辑  收藏  举报