经典问题解析(2)---malloc和new、编译器和构造函数、静态成员
2017-02-23 15:39
369 查看
malloc与free和new与delete有什么区别
程序:#include <cstdlib> #include <iostream> using namespace std; class Test { private: int i; public: Test() { cout<<"Test()"<<endl; i = 0; } Test(int i) { cout<<"Test(int i)"<<endl; this->i = i; } ~Test() { cout<<"~Test"<<endl; } int getI() { return i; } }; void func() { int* p = reinterpret_cast<int*>(malloc(sizeof(int))); //malloc返回的指针为void*类型,需要强制类型转换,申请4个字节的空间 //malloc只能申请空间,不能进行初始化 int* q = new int(10); //定义了一个int变量,值为10 ,new可以做到在申请空间时进行初始化 *p = 5; //*q = 10; cout<<*p<<" "<<*q<<endl; free(p); delete q; cout<<"op:"<<endl; Test* op = reinterpret_cast<Test*>(malloc(sizeof(Test))); //没有打印出构造函数中的内容 //malloc只是负责单纯的申请空间,并不负责调用构造函数 cout<<"oq:"<<endl; Test* oq = new Test; //打印出了构造函数的内容 //new不但申请了空间,而且把这段空间构造成了一个Test类的对象 cout<<"op:"<<op->getI()<<" "<<"oq:"<<oq->getI()<<endl; free(op); delete oq; } int main(int argc, char *argv[]) { func(); cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS; }
1、malloc和free是库函数,以字节为单位申请和释放堆内存。
2、new和delete是关键字,以类型为单位申请和释放堆内存。
3、malloc和free单纯的对内存进行申请与释放。
4、对于基本类型new关键字会对内存进行初始化,为变量赋初值,为类对象调用构造函数。
5、对于类类型new和delete还负责构造函数和析构函数的调用。因此对于new分配的空间,不能使用free进行释放,否则没有析构会造成内存泄漏。
编译器对构造函数的调用
在 现代的 C++编译器看来,上面func函数中的3中类对象的初始化方式是相同的。
C++编译器会尝试各种手段尝试让程序通过编译
方式一:尽力匹配重载函数
方式二:尽力使用函数的默认参数
方式三:尽力尝试调用构造函数进行类型转换
因为拷贝构造函数总是存在的,因此上面的用一个类对象给另一个类对象赋值,总是成功的。
但是一般编译器会采用一种更简单的方式:
编译器会采用方案B的方法,因此上面的程序的运行结果中,没有拷贝构造函数的打印输出。
因此,现代的编译器会把上面的4种方式进行优化,优化为方案B。
“剥夺”编译器对构造函数的调用尝试:
C++提供了explicit关键字用于阻止编译器对构造函数的调用尝试,如果加上explicit关键字,上面的程序会报错。
如果程序这样写,就会产生以下结果:
Test t1(5);//不报错,这是标准的初始化写法 Test t2 = 5;//报错 Test t3 = Test(5);//报错
类的静态成员
对象数目控制需要用到类的静态成员。单例模式的实现:
#include <cstdlib> #include <iostream> using namespace std; //实现单例模式 class Singleton { private: static Singleton* cInstance;//定义一个指针 Singleton()//将构造函数定义为private { } public: static Singleton* GetInstance()//静态成员函数可以访问静态成员变量和其他成员函数 { if( cInstance == NULL )//只能申请一次 { cout<<"new Singleton()"<<endl; cInstance = new Singleton();//创建一个类对象 } return cInstance; } void print() { cout<<"I'm Singleton!"<<endl; } }; Singleton* Singleton::cInstance = NULL; void func() { Singleton* s = Singleton::GetInstance(); Singleton* s1 = Singleton::GetInstance(); Singleton* s2 = Singleton::GetInstance(); cout<<s<<" "<<s1<<" "<<s2<<endl;//三个指针指向的的地址相同 s->print(); } int main(int argc, char *argv[]) { func(); cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS; }
无状态函数:
函数的调用结果只与实参值相关。但是多次调用会浪费时间。
状态函数:
函数的调用结果不仅与实参值相关还与之前的函数调用有关。但是不能回头。
函数对象来实现结合无状态函数和状态函数的优点:
#include <cstdlib> #include <iostream> using namespace std; //三种方法实现斐波那契数列 int fib1(int i)//无状态的函数,比较浪费时间 { int a1 = 0; int a2 = 1; int ret = a2; while( i > 1) { ret = a2 + a1; a1 = a2; a2 = ret; i--; } return ret; } int fib2()//有状态的函数,可以节约计算时间,但是不能回头 { static int a1 = 0; static int a2 = 1; int ret = a2; int t = a2; a2 = a2 + a1; a1 = t; return ret; } class Fib { private: int a1; int a2; public: Fib() { a1 = 0; a2 = 1; } int operator() () //重载()操作符 { int ret = a2; int t = a2; a2 = a2 + a1; a1 = t; return ret; } }; int main(int argc, char *argv[]) { cout<<"int fib1(int i)"<<endl; for(int i=1; i<=10; i++) { cout<<fib1(i)<<endl; } cout<<endl; cout<<"int fib2()"<<endl; for(int i=1; i<=10; i++) { cout<<fib2()<<endl; } cout<<endl; Fib fib;//采用类对象,可以回头从1开始,也可以记录状态 cout<<"Fib fib;"<<endl; for(int i=1; i<=10; i++) { cout<<fib()<<endl;//调用重载操作符 } cout<<endl; cout << "Press the enter key to continue ..."; cin.get(); return EXIT_SUCCESS; }
相关文章推荐
- c++结构体中包含类对象成员的问题 malloc函数不能调用构造函数 new可以
- net学习之类与对象、new关键字、构造函数、常量和只读变量、枚举、结构、垃圾回收、静态成员、静态类等
- C#泛型类的静态构造函数及静态成员[经典]
- .net学习之类与对象、new关键字、构造函数、常量和只读变量、枚举、结构、垃圾回收、静态成员、静态类等
- Java类在new的过程中,静态域、静态块、非静态域、非静态块、构造函数的执行顺序问题
- [对象和类型]8.C#构造函数,怎样用静态方法解决私有构造函数造成的不能new的问题?
- 构造函数初始化成员变量问题
- Effective C# 原则13:用静态构造函数初始化类的静态成员 转
- C++中类的静态数据成员函数解析
- C++中类的静态数据成员函数解析
- C++中类的静态数据成员函数解析[转贴]
- 《Effective C#》Item 13:使用静态构造函数初始化静态成员
- Effective C# 原则13:用静态构造函数初始化类的静态成员(译)
- C++ 编译器默认构造函数奇怪问题
- C++中new(delete)和malloc(free)的常见问题
- Effective C# 原则13:用静态构造函数初始化类的静态成员
- Effective C# 使用静态构造函数初始化静态成员
- ActiveX控件经典问题解析(转)
- 经典String str = new String("abc")内存分配问题
- C++中类的静态数据成员函数解析