C++表达式new和delete

本文深入探讨了C++中new和delete表达式的工作原理,包括内存分配与回收的步骤,operatornew和operatordelete的重载,以及如何通过修改类定义来限制对象的创建方式,仅允许创建栈对象或堆对象。

目录:


一、new表达式工作步骤

二、delete表达式工作步骤

三、operator new 和 operator delete 函数的重载版本

例:两个函数的用法

四、要求一个类只能创建栈对象

例:只能创建栈对象的类

五、要求一个类只能创建堆对象

例:只能创建堆对象的类

六、注意问题

A. 对象销毁和调用析构函数等价吗?A. 栈对象创建时需要哪些条件?





一、new表达式工作步骤


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

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



二、delete表达式工作步骤


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

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



三、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 *);

两个函数的用法:

class Student
{
	public:
	Student(int id, const char * name) 
	: _id(id) 
	, _name(new char[strlen(name) + 1]()) 
	{
		strcpy(_name, name);
		cout << "Student()" << endl;
	}
	
	~Student()
	{
		delete [] _name;
		cout << "~Student()" << endl;
	}
	
	void * operator new(size_t sz)
	{
		void * ret = malloc(sz);
 		return ret;
 	}
 	
 	void operator delete(void * pointer)
 	{
 		free(pointer);
 	}
 	
 	void print() const
 	{
 		cout << "id:" << _id << endl
 			 << "name:" << _name << endl;
 	}
 	
private:
	int _id;
	char * _name;
};

int main(void)
{
	Student * stu = new Student(100, "Jackie");
	stu->print();
	delete stu;
	return 0;
}



四、要求一个类只能创建栈对象


如果要求一个类只能创建栈对象,其意思是在创建出栈对象的同时,不能创建堆对象。以Student类型 而言:

void test0() 
{
	Student s1(101, "John");//ok 
	Student * stu = new Student(101, "Mark");//error
}

要达到以上的效果,只需要 将operator new放入Student类的private区域。


例:只能创建栈对象的类

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

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

class Student
{
public:
    Student(int id, const char *name)
    : _id(id)
    , _name(new char[strlen(name) + 1]())
    {
        cout << "Student()" << endl;
        strcpy(_name, name);
    }

    void print() const
    {
        cout << "id : " << _id << endl
             << "name : " << _name << endl;
    }
    
private:
    void *operator new(size_t sz)
    {
        cout << "new()" << endl;
        void *pret = malloc(sz);
        return pret;
    }

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

int main(int argc, char **argv)
{
    Student stu(56, "Janell");//栈对象
    stu.print();
    // Student *pstu = new Student(12, "xiaoming");
    return 0;
}



五、要求一个类只能创建堆对象

如果要求一个类只能创建堆对象,其意思是在创建出堆对象的同时,不能创建栈对象。以Student类型 而言,

void test1()
{
	Student s1(101, "John");//error
	Student * stu = new Student(101, "Mark");//ok
}

要达到以上的效果,只需要 将Student类的析构函数放入private区域。

例:只能创建堆对象的类

将析构函数放入private区域,为了清理,可以添加函数 destory() ,函数 destory() 执行 delete this; ,删除对象本身,包括数据成员的堆空间(析构函数)和对象本身堆空间(delete 函数重载)

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

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

class Student
{
public:
    Student(int id, const char *name)
    : _id(id)
    , _name(new char[strlen(name) + 1]())
    {
        cout << "Student()" << endl;
        strcpy(_name, name);
    }

    void print() const
    {
        cout << "id : " << _id << endl
             << "name : " << _name << endl;
    }

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

    void destroy()
    {
    	//删除对象本身
        delete this;
    }
private:
    ~Student()
    {
        cout << "~Student()" << endl;
        if(_name)
        {
            delete [] _name;
            _name = nullptr;
        }
    }
private:
    int _id;
    char *_name;
};

int main(int argc, char **argv)
{
    //Student stu(56, "xiaohong"); //error
    Student *pstu = new Student(12, "xiaoming");
    pstu->print();
    pstu->destroy();
    return 0;
}



六、注意问题


A. 对象销毁和调用析构函数等价吗?

Q: 不等价,析构函数是对象销毁的其中一步,对象销毁既要 调用析构函数回收对象中数据成员所申请的资源 等,又要 释放该对象所用的内存(彻底销毁对象)

假如将之前例子中的 new / delete 函数重载放到类外,创建回收对象的堆空间,以及对象成员申请释放的堆空间将会调用两次 new / delete 函数;
而将 new / delete 函数重载放到类内,将只有一次(构造 / 析构函数)。


A. 栈对象创建时需要哪些条件?

Q: 构造函数和析构函数都为非私有

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值