学完C语言动态内存管理 和 C++动态内存管理我们就应该深入的去对比和了解两个的特性。
一 、 malloc/free和new/delete异同点
共同点:都是从堆上开辟空间,最后都需要手动释放
不同点:
- malloc/delete是标准库函数,new/delete是操作符
- new创建对象时会调用构造函数+开空间 ;delete会调用析构函数,而malloc/free只会开空间,而不会调用构造函数和调用析构函数
- malloc/free需要手动计算类型大小且返回值是 void*,在使用时必须强转 ,而new/delete可以自动计算空间并且返回对应类型的指针。
- malloc申请空间失败时返回NULL,因此在申请完之后必须判空,new不需要,但是new有出错会有异常捕获
- malloc申请的空间一定在堆上,new不一定(也有可能会在栈上),因为operator new函数可以重新实现
- new/delete比malloc/free效率要低,因为new/delete底层封装的是malloc/free。
二 、设计一个类,该类只能在堆上创建对象
分析:我们在用在函数内部定义变量----是在栈上开辟空间,若在全局区创建变量------则在数据段开辟空间
我们唯一知道能在堆上创建变量只有malloc相关函数,但是,malloc不会调用构造函数,pass。
那么我们到底要怎么做呢?
1.将构造函数作为私有成员,拷贝构造申明为私有成员,防止其他人调用在栈上创建对象
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建
class Test
{
public:
static Test* CreatObj()
{
return new Test;
}
private:
//将构造函数申明为私有
Test() {};
//防拷贝,但是这样是存在一个缺陷的,如果类中有friend函数该做法就会失效
//这里我们只声明,不实现。因为实现可能会很麻烦,而我们本身可能不需要
Test(const Test&t);
//C++11提供的完美解决办法----删除函数
Test(const Test&t) = delete;
private:
int _data;
};
int main()
{
Test *pt = Test::CreatObj();
/*Test obj;
Test obj3(*pt);*/
return 0;
}
三 请设计一个类,该类只能在栈上创建对象
这个就比较简单了,只能在栈上创建对象,即不能再对上创建对象,这样的话我们只需要将new的功能屏蔽掉即可,当然operator new 和 定位new表达式也会随之屏蔽。
class StackType
{
public:
static StackType CreatStackObj()
{
StackType obj;
return obj;
}
void Print()
{
cout << "StackType::Print()" << endl;
}
private:
StackType()
{}
//将operator new 和 定位new表达式 功能屏蔽
void* operator new(size_t n) = delete;
void operator delete(void* p) = delete;
};
int main()
{
StackType::CreatStackObj().Print(); // 相当于一个类
StackType obj = StackType::CreatStackObj();
obj.Print();
return 0;
}