C/C++之动态内存分配比较

1、C malloc 和 free vs C++ new 和delete:

C 语言的malloc() 和free() 并不会调用析构函数和构造函数。C++的 new 和 delete 操作符 是 "类意识" ,并且当调用new的时候会调用类的构造函数和当delete 调用的时候会调用析构函数。

下面一个例子

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
using namespace std;

class SS
{
public:
	SS();
	~SS();
private:
	int ff;
	int gg;
};
SS::SS()
{
	ff=5;
	cout << "Constructor called" << endl;
}
SS::~SS()
{
	cout << "Destructor called" << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
	SS *ss;
	ss = new SS;  // new operator calls constructor.
	delete ss;    // delete operator calls destructor.
	return 0;
}

运行结果:

如图一

 注意:混合用malloc 和delete或者混合用new 和free 是不正确的。C++的new和delete是C++用构造器分配内存,用析构函数清除使用过的内存。

new/delete 优点:

  • new/delete调用 constructor/destructor.Malloc/free 不会.
  • new 不需要类型强制转换。.Malloc 要对放回的指针强制类型转换.
  • new/delete操作符可以被重载, malloc/free 不会
  • new 并不会强制要求你计算所需要的内存 ( 不像malloc)

2、C 的动态内存分配:

看如下例子MallocTest.cpp

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
using namespace std;

typedef struct
{
	int ii;
	double dd;
} SSS;


int _tmain(int argc, _TCHAR* argv[])
{
int kk, jj;
char *str1="This is a text string";
char *str2 = (char *)malloc(strlen(str1));

SSS *s1 =(SSS *)calloc(4, sizeof(SSS));
if(s1 == NULL) printf("Error ENOMEM: Insufficient memory available\n");
strcpy(str2,str1); //Make a copy of the string 
for(kk=0; kk < 5; kk++)	
{
s1[kk].ii=kk;
}
for(jj=0; jj < 5; jj++)
{
printf("Value strored: %d\n",s1[jj].ii);
}
free(s1);
free(str1);
free(str2);

}

 结果:

图二

注意:

  • malloc: 用于申请一段新的地址
  • calloc: 用于申请N段新的地址
  • realloc: realloc是给一个已经分配了地址的指针重新分配空间
  •  free: 通过指针释放内存

3、C++ 动态内存分配:

 

使用 "new" 和 "delete"

如下示例:文件: AllocNewTest.cpp

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
using namespace std;

class CCC

{
public:
	CCC(){cout<<"CCC()"<<endl;};
	~CCC(){cout<<"~CCC()"<<endl;};
	CCC(int);
	CCC(int, double);
	int ii;
	double dd;
};
CCC::CCC(int _ii)
: ii(_ii)
{
};

CCC::CCC(int _ii, double _dd)
: ii(_ii), dd(_dd)
{
};



int _tmain(int argc, _TCHAR* argv[])
{
	CCC *cc1 = new CCC(4, 5.5);   // Pointer. Contructor called.
	CCC *cc2 = new CCC[5];        // Pointer to an array of objects.
	CCC &cc3 = *new CCC;          // Reference
	CCC **c4 = new CCC * [5];     // Array of pointers to pointers
	cc1->ii   = 5;
	cc2[3].ii = 6;

	cc3.ii    = 7;
	c4[0]     = new CCC(8);
	c4[1]     = new CCC(9);

	cout << cc1->ii   << endl;
	cout << cc2[3].ii << endl;
	cout << cc3.ii    << endl;
	cout << c4[0]->ii << endl;
	cout << c4[1]->ii << endl;
	delete cc1;
	delete [] cc2;
	delete & cc3;

	delete [] c4[0];   // First delete pointer content
	delete [] c4[1];
	delete [] c4;      // then delete array of pointers
	return 0;

}

注意:

  •  new CCC(3) 为integer 成员的单个对象分配的内存并且设置integer 成员成3.
  •  new CCC[3] 创建三个对象,并没有初始化变量

结果如图:

图四

4、C 函数返回一个指针vs C++函数返回的是一个副本:

C 函数返回一个指针 

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

char *fnConvert(int _ii)
{
	char *str =(char*)malloc(10);  /* Return 10 character string */
	if(str == NULL)
		fprintf(stderr,"Error: Memory allocation failed.\n");
	sprintf(str, "%d", _ii);
	return str;
}

int _tmain(int argc, _TCHAR* argv[])
{
	char *s1=fnConvert( 34567 );
	printf("%s\n", s1);
	free(s1);
	return 0;

}

运行结果:

图五

C++ 函数返回的是一个副本:

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

string fnConvert(int _ii)

{
	ostringstream ost;
	ost << _ii;
	return ost.str();
}


int _tmain(int argc, _TCHAR* argv[])
{
	 cout << fnConvert( 34567 ) << endl;
	return 0;

}

 运行结果

图六

注意:c++的STL string类的赋值构造函数是被用来返回一个值的副本,也就是当我们离开了函数的时候,变量 "ost",不在作用域了,但是所赋复制的内容是有效的。不要返回"return ost.str().c_str()" 作为他的指针,他是不在作用域的内一旦程序离开了函数,并且数据会丢失。

5、C++ 动态内存分配的异常处理: 

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
	int ii;
	double *ptr[5000000];
	try
	{
		for( ii=0; ii < 5000000; ii++)
		{
			ptr[ii] = new double[5000000];
		}
	}
	catch ( bad_alloc &memmoryAllocationException )
	{
		cout << "Error on loop number: " << ii << endl;
		cout << "Memory allocation exception occurred: "
			<< memmoryAllocationException.what()
			<< endl;
	}
	catch(...)
	{
		cout << "Unrecognized exception" << endl;
	}
	return 0;

}

 运行:

  • 观察系统约束: ulimit -a
  • 设置系统约束: ulimit -m 100
  • 以很小的优先权运行: nice -n 19 AllocNewTest

6、C++ Virtual Destructors

// memory.cpp : 定义控制台应用程序的入口点。
//2011/10/13 by wallwind

#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>
using namespace std;

class Base
{
public:
	Base(){};
	virtual ~Base(){ cout << "Base class destructor called" << endl; }
};

class Derived : public Base
{
public:
	Derived(){};
	~Derived(){ cout << "Derived class destructor called" << endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
	Base *ptr = new Derived();
	delete ptr;
	return 0;

}


运行结果:

图七

注意:

  • 如果删除操作符被应用在基类中,并且其析构函数并不是虚函数,这将会引起内存泄露,因为只有基类的内存被释放掉。
  • 基类的析构函数不是纯虚函数,将不能被作为基类而实现。
  • 类的析构函数可以不是virtual

 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wallwind/article/details/6868665
个人分类: C/C++学习
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭