一、题目
1、 malloc/free和new/delete共同点和不同点
- 共同点时都在堆上申请空间,都需要手动释放空间
- malloc和free是函数,new和delete是操作符
- malloc申请空间时需要手动计算申请空间大小,而new只需在后面跟上空间类型即可
- malloc返回值时void*,在使用时强转,new不需要
- malloc申请空间失败返回NULL,在使用时必须判断是否为空,而new不需要,new在失败时会抛异常
- malloc/free只能申请内置类型的空间,不能申请自定义类型空间,因为不会调用构造函数和析构函数,而new在申请完空间后会调用构造函数,delete在释放空间前会调用析构函数
- malloc申请的空间一定在堆上,new不一定,因为operator new函数会重新实现
- new/delete比malloc/free的效率稍微低点,因为new/和delete底层封装了malloc/free(面试时可以不说因为说了后就是坑需要你自己填坑,当然大佬忽略)
2、设计一个只能在堆或栈上创建对象的类
首先我们得明白栈中存放非静态局部变量、函数参数、返回值等等,堆用于动态分配;new在申请自定义类型空间时,会先调用operator new,再调用构造函数,delete在申请自定义空间时,会先调用析构函数,再调用operator delete;我们说operator new是调用malloc来申请空间,operator delete是调用free来申请空间
(1)只在堆上
当只在堆上创建对象时,不能调用静态建立类对象,只需把构造函数有化即可
(2)只在栈上
当只在栈上创建对象时,既不调用new运算符,只需把operator new和operator delete私有化即可
3、单例模式
一个类只能创建一个对象,即单例模式,该模式保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该列被所有的程序模块共享
(1)饿汉模式
不管用不用,程序启动就创建一个唯一的实例对象,如果此对象在多线程高并发环境下频繁使用,这种模式响应速度会更好
(2)懒汉模式
由于饿汉模式有时十分占用资源导致启动慢,而且创建的对象有可能不会用到,所以我们使用懒汉模式,就是延迟加载会更好;此模式我们需要用到互斥锁
4、内存泄漏
(1)什么是内存泄漏
内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用内存的情况,内存泄漏并不是指内存物理上的消失,而是指对该段内存失去了控制
(2)内存泄漏分类
- 堆内存泄漏:指程序执行过程中通过malloc、calloc、realloc、new等从堆中分配的一块内存用完后没有调用对应的free或delete删掉,导致这段内存未被释放,那么以后这块内存无法被利用,会产生Heap Leak
- 系统资源泄漏:指程序使用系统分配的资源,比如方套接字、文字描述符、管道等没有使用对应的函数释放掉,导致系统资源浪费,严重可导致系统效能减少,系统执行不稳定
(3)如何解决内存泄漏
- 事前预防:良好的设计规范,良好的编码规范,申请的空间匹配的取释放,利用智能指针
- 事后查错:泄漏检测工具
.二、源代码
//只在堆上创建对象
#include <iostream>
using namespace std;
class HeapOnly
{
public:
static HeapOnly* CreateObject()
{
return new HeapOnly;
}
private:
HeapOnly(){}
HeapOnly(const HeapOnly&);
};
int main()
{
HeapOnly* obj2 = HeapOnly::CreateObject();
return 0;
}
//只在栈上创建对象
#include <iostream>
using namespace std;
class StackOnly
{
public:
StackOnly(){}
~StackOnly(){}
private:
void* operator new(size_t);
void operator delete(void*);
};
int main()
{
StackOnly obj1;
return 0;
}
//单例模式——饿汉模式
#include<iostream>
using namespace std;
class Hungry
{
public:
static Hungry* GetInstance()
{
return &_instance;
}
private:
Hungry(){}
Hungry(const Hungry&){}
static Hungry _instance;
};
Hungry Hungry::_instance;//在程序入口就完成单例对象的初始化
int main()
{
return 0;
}
//单列模式——懒汉模式
#include<iostream>
#include<mutex>
using namespace std;
class Lazy
{
public:
static Lazy* Getinstance(){
//使用Double-Check加锁,保证效率和线程安全
if (nullptr == _instance){
_mtx.lock();
if (nullptr == _instance){
_instance = new Lazy();
}
_mtx.unlock();
}
return _instance;
}
//创建一个垃圾回收的内部类
class Clean{
public:
~Clean(){
if (Lazy::_instance)
delete Lazy::_instance;
}
};
//定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数释放单例对象
static Clean Getclean;
private:
Lazy(){};
Lazy(const Lazy&);
static Lazy* _instance;//单例对象指针
static mutex _mtx; //互斥锁
};
Lazy* Lazy::_instance = nullptr;
Lazy::Clean GetClean;
mutex Lazy::_mtx;
int main()
{
return 0;
}