C++中的new、operator new与placement new

new operator

new operator是我们常用的new。

new 和 delete 是用来在 堆上申请和释放空间的 ,是 C++ 定义的 关键字,和 sizeof 一样。

实际 new / delete 和 malloc / free 最大的区别是,前者对于 自定义类型 除了可以开辟空间,还会调用构造和析构函数

  1. 分配内存,如果类A重载了operator new,那么将调用A::operator new(size_t )来完成,如果没有重载,就调用::operator new(size_t ),即全局new操作符来完成

  2. 调用构造函数生成类对象;

  3. 返回相应指针

1.operator new、operator delete就是对malloc和free的封装

2.operator new中调用malloc开辟空间失败后,改为抛异常处理,这种处理更符合C++处理错误的方式

new 的原理

Ⅰ. 调用 operator new 函数申请空间

Ⅱ. 在申请的空间上执行构造函数,完成对象的构造

delete 的原理

Ⅰ. 在空间上执行析构函数,完成对象中资源的清理工作

Ⅱ. 调用 operator delete 函数释放对象的空间

new T[N] 的原理

Ⅰ. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申请

Ⅱ. 在申请的空间上执行 N 次构造函数

delete[] 的原理

Ⅰ. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理

Ⅱ. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间

operator new

operator new是一个操作符,和+ -操作符一样,作用是分配空间。我们可以重写它们,修改分配空间的方式。

operator new返回值必须是void*。第一个参数必须是size_t

void* operator new (std::size_t size) throw (std::bad_alloc);  
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw(); 

在下面的例子中,我们使用重载了三个operator new方法, 并分别调用。

#include <iostream>
#include <string>
#include <malloc.h>
using namespace std;

//student class
class Stu
{
public:
    Stu(string name, int age)
    {
        cout << "call Stu class constructor" << endl; 
        name_ = name;
        age_ = age;
    };
public:
    void print() const
    {
        cout << "name = " << name_ << std::endl;
        cout<< "age = " << age_ << std::endl;
    };
    void* operator new(size_t size)
    {
        std::cout << "call operator new" << std::endl;
        return malloc(size);
    }
    void* operator new(size_t size, int num)
    {
        std::cout << "call operator new with int" << std::endl;
        return malloc(size);
    } 
    void* operator new(size_t size, char c)
    {
        std::cout << "call operator new with char" << std::endl;
        return malloc(size);
    }      
private:
    string name_;
    int age_;
};
int main()
{
    Stu* stu1 = new Stu("a", 10);
    Stu* stu2 = new(1) Stu("a", 10);
    Stu* stu3 = new('c') Stu("a", 10);
}

placement new

placement new是operator new的一种重载形式,其作用是可以在指定的内存地址创建对象。

placement new返回值必须是void*。第一个参数必须是size_t, 第二个参数是void*。

void* operator new (std::size_t size, void* ptr) throw();

下面的是一个关于placement new的调用例子:

#include <iostream>
#include <string>
#include <malloc.h>
using namespace std;

//student class
class Stu
{
public:
    Stu(string name, int age)
    {
        name_ = name;
        age_ = age;
    };
public:
    void print() const
    {
        cout << "name = " << name_ << std::endl;
        cout<< "age = " << age_ << std::endl;
    };
    void* operator new(size_t size, void* p)
    {
        std::cout << "placement new" << std::endl;
        return p;
    };    
private:
    string name_;
    int age_;
};
int main()
{
    void* stu1 = (Stu*)malloc(sizeof(Stu));
    new (stu1) Stu("stu1", 10);
    ((Stu*)stu1)->print();
}

由于placement new可以在一个指定的位置创建对象,因此在STL中有很广泛的运用, 例子vector容器初始化的时候,会使用allocator申请一定的内存,当使用push_back放入对象时, 就可以使用placement new在申请的位置创建对象。

结论

对于new, operator new 和 placement new三者的区别, 我们总结如下:

new:

new是一个关键字,不能被重载。

new 操作符的执行过程如下:

  • 调用operator new分配内存 ;

  • 调用构造函数生成类对象;

  • 返回相应指针。

operator new:

operator new就像operator + 一样,是可以重载的。

如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。

同理,operator new[]、operator delete、operator delete[]也是可以重载的。

placement new:

placement new和operator new并没有本质区别。它们都是operator new操作符的重载,只是参数不相同。

placement并不分配内存,只是返回指向已经分配好的某段内存的一个指针。因此不能删除它,但需要调用对象的析构函数。

如果你想在已经分配的内存中创建一个对象,使用new时行不通的。

也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void* p实际上就是指向一个已经分配好的内存缓冲区的的首地址。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/192228.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言基础篇5:指针(二)

接上篇&#xff1a;C语言基础篇5&#xff1a;指针(一) 4 指针作为函数参数 4.1 指针变量作为函数的参数 指针型变量可以作为函数的参数&#xff0c;使用指针作为函数的参数是将函数的参数声明为一个指针&#xff0c;前面提到当数组作为函数的实参时&#xff0c;值传递数组的地址…

其利天下技术总监冯建武受邀出席“2023年电子工程师大会”并作主题演讲

2023年11月23日&#xff0c;由华秋电子发烧友主办的“2023年电子工程师大会暨第三届社区年度颁奖活动”在深圳新一代产业园成功举行。本次年度颁奖活动邀请了高校教授、企业高管、行业专家、资深电子工程师等共300多人出席。聚焦“电机驱动技术”、“开源硬件”、“OpenHarmony…

C#学习-8课时

P10 输入输出程序编写 相同类型的可以直接相加&#xff1b; cwtabtabconsole.Writeline(); using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace C_8_1 { class Program { s…

【腾讯云云上实验室】用向量数据库—实践相亲社交应用

快速入口 &#x1f449;向量数据库_大模型知识库_向量数据存储_向量数据检索- 腾讯云 (tencent.com) 文章目录 前言1. 向量数据库概念及原理1.1 向量数据库概念1.2 向量数据库核心原理1.3 向量数据库优缺点1.4 向量数据库与传统数据库的区别 2. 腾讯云向量数据库的基本特性及优…

黑马程序员索引学习笔记

文章目录 索引的分类从索引字段特性从物理存储从数据结构组成索引的字段个数 InnoDB主键索的Btree高度为多高呢?explain执行计划最左匹配原则索引失效情况SQL提示覆盖索引、回表查询前缀索引索引设计原则 索引的分类 从索引字段特性 主键索引、唯一索引、常规索引、全文索引…

RNN 网络结构及训练过程简介

本文通过整理李宏毅老师的机器学习教程的内容&#xff0c;简要介绍 RNN&#xff08;recurrent neural network&#xff09;的网络结构及训练过程。 RNN 网络结构, 李宏毅 RNN RNN 的特点在于存储功能&#xff0c;即可以记忆前面时刻的信息。 最简单的 RNN 结构如下&#xf…

切换服务器上自己用户目录下的 conda 环境和一个外部的 Conda 环境

如果我们有自己的 Miniconda 安装和一个外部的 Conda 环境&#xff08;比如一个全局安装的 Anaconda&#xff09;&#xff0c;我们可以通过修改 shell 环境来切换使用它们。这通常涉及到更改 PATH 环境变量&#xff0c;以便指向你想要使用的 Conda 安装的可执行文件&#xff1a…

CSS新手入门笔记整理:CSS基本选择器

id属性 id属性具有唯一性&#xff0c;也就是说&#xff0c;在一个页面中相同的id只能出现一次。在不同的页面中&#xff0c;可以出现两个id相同的元素。 语法 <div id"text"> ...... </div> class属性 class&#xff0c;顾名思义&#xff0c;就是“类…

C语言每日一题(37)两数相加

力扣网 2 两数相加 题目描述 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&a…

【Linux】第二十一站:文件(一)

文章目录 一、共识原理二、C系列文件接口三、从C过渡到系统&#xff1a;文件系统调用四、访问文件的本质 一、共识原理 文件 内容 属性 文件分为打开的文件 和 没打开的文件 打开的文件&#xff1a;是谁打开的&#xff1f;是进程&#xff01;----所以研究打开的文件本质是研…

Redis之C语言底层数据结构笔记

目录 动态字符串SDS Dict ZipList QuickList ​ SkipList 动态字符串SDS Dict ZipList QuickList SkipList

SAP创建ODATA服务-Structure

SAP创建ODATA服务-Structure 1、创建数据字典 进入se11创建透明表ZRICO_USR,并创建对应字段 2、创建OData service 首先创建Gateway service project&#xff0c;事务码&#xff1a;SEGW&#xff0c;点击Create Project 按钮 Gateway service Project分四个部分&#xff1a…

ubuntu20.04安装tensorRT流程梳理

目标&#xff1a;先跑demo&#xff0c;再学习源码 step1, 提前准备好CUDA环境 安装CUDA&#xff0c;cuDNN 注意&#xff0c;CUDA&#xff0c;cuDNN需要去官网下载.run和tar文件安装&#xff0c;否则在下面step4 make命令会报找不到cuda等的错误&#xff0c;具体安装教程网上…

COMP2121 Discrete Mathematics

COMP2121 Discrete Mathematics 需要可WeChat: zh6-86

Unity 打印每次代码保存耗时

unity每次编辑代码的时候&#xff0c;都需要保存&#xff0c;unity右下角的小圆圈总是转个不停&#xff0c;那么每次编辑代码后&#xff0c;unity到底需要多久时间呢&#xff0c;下面就有代码可以获取 保存时间。 using UnityEngine; using UnityEditor; using UnityEditor.Com…

开源万能DIY预约小程序源码系统+自由DIY,海量模板任选择,附带完整的搭建教程

在移动互联网时代&#xff0c;用户对于预约服务的便捷性和高效性需求日益增长。为了满足这一需求&#xff0c;我们凭借多年的技术积累和经验&#xff0c;开发出了这款开源万能DIY预约小程序源码系统。该系统的推出旨在帮助开发者快速构建功能丰富、符合用户需求的预约小程序&am…

四、IDEA创建项目时,Maven Archetype模板工程说明

什么是Maven Archetype Archetype是一个Maven项目的模板工具包&#xff0c;它定义了一类项目的基本架构。Archetype为开发人员提供了创建Maven项目的模板&#xff0c;同时它也可以根据已有的Maven项目生成参数化的模板。 官方文档&#xff1a;https://maven.apache.org/archet…

fastjson和jackson序列化的使用案例

简单记录一下一个fastjson框架和jackson进行序列化的使用案例&#xff1a; 原json字符串&#xff1a; “{“lockCount”:”{1:790,113:1,2:0,211:0,101:1328,118:8,137:0,301:0,302:0}“,“inventoryCount”:”{1:25062,113:2,2:10000,211:2,101:11034,118:9,137:40,301:903914…

【一起来学kubernetes】7、k8s中的ingress详解

引言配置示例负载均衡的实现负载均衡策略实现模式实现方案Nginx类型Ingress实现Treafik类型Ingress实现HAProxy类型ingress实现Istio类型ingress实现APISIX类型ingress实现 更多 引言 Ingress是Kubernetes集群中的一种资源类型&#xff0c;用于实现用域名的方式访问Kubernetes…