经典问题解析(2)---malloc和new、编译器和构造函数、静态成员
来源:互联网 发布:sql server 分组求和 编辑:程序博客网 时间:2024/05/14 12:42
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;}
0 0
- 经典问题解析(2)---malloc和new、编译器和构造函数、静态成员
- malloc函数和new
- C++编译器处理成员函数和静态成员
- js构造函数的静态成员和实例成员
- c++:静态成员变量和静态成员函数使用问题
- c++结构体中包含类对象成员的问题 malloc函数不能调用构造函数 new可以
- Javascript构造函数,公有,私有特权和静态成员
- javascript构造函数中的公有,私有,特权和静态成员
- C++中静态成员变量与静态成员函数,以及malloc , free , new , delete ,区别
- 静态函数和静态成员
- C#泛型类的静态构造函数及静态成员[经典]
- new和malloc的区别深入解析
- net学习之类与对象、new关键字、构造函数、常量和只读变量、枚举、结构、垃圾回收、静态成员、静态类等
- 构造函数和成员函数
- 静态成员变量和静态成员函数
- 静态成员和静态成员函数
- 静态成员和静态成员函数
- 静态数据成员和静态成员函数
- flexbox属性总结
- BAT+华为SP面经,聊一些细节加分项
- 字符串模式匹配算法(字符串搜索)
- lotus domino 空字符的判定
- JS+PHP仿CMD命令行控制台
- 经典问题解析(2)---malloc和new、编译器和构造函数、静态成员
- 35 个 Java 代码性能优化总结
- Android string.xml如何输入空格、换行等符号——转义字符
- 主仆模式(Master-Slave)
- setInterval()和setTimeout()定时器的区别
- React Native 从入门到原理
- makefile 将生成的目标文件和可执行文件存放在指定的目录下
- windows下bat批处理实现守护进程(有日志)
- 时域卷积与频域乘积