new和delete工作机制

C++中创建堆对象时,我们要使用new/delete,那么它们具体做了什么?现在深入讨论。

1. new表达式工作步骤

使用new表达式时发生的三个步骤:

  1. 调用名为operator new的标准库函数来分配足够大的原始的未类型化的堆空间,以保存指定类型的一个对象;
  2. 运行该类型的一个构造函数初始化对象;
  3. 返回指向新分配并构造的构造函数对象的指针。

2. delete表达式工作步骤

使用delete表达式时发生的两个步骤:

  1. 调用析构函数,回收对象中数据成员所申请的资源;
  2. 调用名为operator delete的标准库函数来释放该对象本身所占用的内存。

3. operator new和operator delete函数的重载

//operator new库函数
void *operator new(size_t);
void *operator new[](size_t);

//operator delete库函数
void operator delete(void *);
void operator delete[](void *);

通过例子说明:

#include <string.h>
#include <stdlib.h>
#include <iostream>

using std::cout;
using std::endl;

void *operator new(size_t sz) 
{
    cout << "void *operator new(size_t)" << endl;
    void *pret = malloc(sz);
    return pret;
}

void operator delete(void *ptr)
{
    cout << "void operator delete(void *)" << endl;
    free(ptr);
}

class Student
{
public:
    Student(int id, const char* name)
    : _id(id)
    , _name(new char[strlen(name)+1]())
    {
        cout << "Student(int, char*)" << endl;
        strcpy(_name, name);
    }
#if 0
    void *operator new(size_t sz)//等价:static void *operator new(size_t sz)
    {
        cout << "void *operator new(size_t)" << endl;
        
        /*Q:成员函数operator new/delete里面包含this没有?
        /*A: printf("this: %p\n", this); error,类中默认是静态成员函数*/
       
        //申请的原始的未初始化的空间
        void *pret = malloc(sz);
        return pret;
    }

    static void operator delete(void *ptr)//等价:void operator delete(void *ptr)
    {
        cout << "void operator delete(void *)" << endl;
        free(ptr);
    }
#endif
    void print() const
    {
        if(_name)
        {
            cout << "(id = " << _id << ", "
                << "name = " << _name 
                << ")" << endl;
        }
    }

    ~Student()
    {
        cout << "~Student()" << endl;
        if(_name)
        {
            delete [] _name;
            _name = nullptr;
        }
    }
private:
    int _id;
    char* _name;
};

void test()
{
    Student *pstu = new Student(4306, "xiaozhang");//堆对象
    pstu->print();
    /*
    A:对象的销毁与析构函数的执行是不是等价呢?
    Q:如果是栈对象,那么对象的销毁与析构函数的执行就是等价的;
    对于堆对象而言,对象的销毁会执行析构函数,但析构函数的执行
    只是对象销毁中的一个步骤。
    */
    delete pstu;
    pstu = nullptr;
}

int main(int argc, char* argv[])
{
    test();
    return 0;
}

运行结果分析:
在这里插入图片描述
在这里插入图片描述

经过上述的讨论,结合new和delete工作机制,现在有两个问题:
Q1:如果要求一个类只能创建栈对象,怎么处理?(其意思是在创建出栈对象的同时,不能创建堆对象)
A1:不能简单的将构造函数设置为私有,否则栈对象、堆对象都无法创建,解决方案是将operator new库函数设置为私有的。

Q2:如果要求一个类只能创建堆对象,怎么处理?(其意思是在创建出堆对象的同时,不能创建栈对象)
A2:由于创建栈对象的条件需要将构造函数和析构函数设置为public,可以将析构函数设置为私有。而销毁堆对象时会有报错,可以有类似如下操作:

class Student
{

//...

void destroy()
    {
        /*this->~Student();//显示调用析构函数*/
        delete this;
    }
private:
    ~Student()
    {
        cout << "~Student()" << endl;
        /* delete this;error,栈溢出*/
        if(_name)
        {
            delete [] _name;
            _name = nullptr;
        }
    }
 }

//...

	pstu->destroy();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值