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

news2024/11/24 14:08:09

new operator

当我们使用了new关键字去创建一个对象时,你知道背后做了哪些事情吗?

A* a = new A;

实际上这样简单的一行语句, 背后做了以下三件事情:

  1. 分配内存,如果类A重载了operator new,那么将调用A::operator new(size_t )来完成,如果没有重载,就调用::operator new(size_t ),即全局new操作符来完成
  2. 调用构造函数生成类对象;
  3. 返回相应指针。

下面我们通过一个例子来验证这个过程:

#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);
    }
private:
    string name_;
    int age_;
};
int main()
{
    Stu* stu1 = new Stu("a", 10);
}

在上述代码中,我们重载了Stu类的operator new操作符,用来验证上述的结论。

上述代码的执行结果如下所示:

call operator new
call Stu class constructor

可以看到重载的operator new被调用,类Stu的构造函数也被调用,验证了上述的描述。

要注意到的是new是一个关键字,和sizeof一样,我们不能修改其具体功能。

operator new

从new的调用过程中,我们知道会调用operator new操作符

那么operator new又是什么呢?

C++支持运算符的重载,支持对一些运算符自定义其行为:

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);
}

执行结果如下:

call operator new
call Stu class constructor
call operator new with int
call Stu class constructor
call operator new with char
call Stu class constructor

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
name = stu1
age = 10

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

这里以MyTinySTL中创建对象的函数为例,construct.h, 可以看出construct函数就是使用了全局的placement new方法在指定地址创建对象。

template <class Ty, class... Args>
void construct(Ty* ptr, Args&&... args)
{
  ::new ((void*)ptr) Ty(mystl::forward<Args>(args)...);
}

结论

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

new

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

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

  1. 调用operator new分配内存 ;
  2. 调用构造函数生成类对象;
  3. 返回相应指针。

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实际上就是指向一个已经分配好的内存缓冲区的的首地址。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TencentOS安装并运行多版本php

TencentOS版本3.1安装并运行php7&#xff0c;现在需要同时运行一个php8. php选择使用了php v8.0.27 采用编译安装的方式&#xff0c;编译命令如下&#xff1a; ./configure --prefix/application/php8 --with-config-file-path/application/php8/etc --with-mhash --with-o…

51单片机学习笔记-4矩阵键盘

4 矩阵键盘 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 4.1 矩阵键盘介绍 在键盘中按键数量较多时&#xff0c;为了减少I/O口的占用&#…

vuex中 this.$store.dispatch() 与 this.$store.commit()

一、理解 this.$store.dispatch 分发 actions-> 调用 mutations->改变 states 二、思考 1、为什么不直接分发 mutation mutation 有必须同步执行的限制&#xff0c;而 Action 不受约束&#xff0c;可以在 action 内部执行异步操作2、Action 通常是异步的&#xff0c;…

配置日志输出到指定位置的文件,单独报错error级别以上的日志,按日志类别打印日志

目录1.配置文件2.测试程序&#xff1a;工具&#xff1a;log4j的jar包、配置文件log4j.properties(文件名自定义)、eclipse或IDEA 更多参考&#xff1a;https://www.cnblogs.com/ITtangtang/p/3926665.html、 1.配置文件 新建一个配置文件log4j.properties&#xff08;我把它放…

区块链游戏走出一地鸡毛,元宇宙3D国风链游或成最大受益者

曾推出过《Cytus》《Deemo》《聚爆》等知名游戏的雷亚&#xff0c;其CEO游名扬在接受采访时曾谈到&#xff0c;游戏产业是文化产业加上科技产业的组合体&#xff0c;这两者是组成游戏产业的主要部分。看游戏的趋势&#xff0c;就要针对文化和科技的趋势上来看。 这话没错。 20…

flutter StreamController,ValueListenableBuilder,NotificationListener

FutureBuilder &#xff08;异步数据更新&#xff09; StreamBuilder &#xff08;异步数据更新&#xff09; 构造函数 特点 接收多个异步操作的结果class StreamBuilder<T> extends StreamBuilderBase<T, AsyncSnapshot<T>>{}单订阅&#xff1a;StreamCo…

在Linux中进行Hbase搭建

在公网IP为x.x.x.x、y.y.y.y和z.z.z.z并装有Centos8的服务器上进行hadoop集群搭建、zookeeper集群搭建和hbase搭建&#xff0c;都安装hadoop-3.1.3、server-jre-8u202-linux-x64、apache-zookeeper-3.6.4-bin和hbase-2.5.0-bin。 环境准备&#xff08;三台服务器都一样&#x…

基于javaweb宠物领养平台管理系统设计和实现

基于javaweb宠物领养平台管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方…

C++基础——C++ 判断

C基础——C 判断C 判断判断语句C if 语句语法流程图? : 运算符C 判断 判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句&#xff08;可选的&#xff09;。 下面是大多数编…

DAMA数据管理知识体系指南之数据管理概述

第2章 数据管理 2.1 引言 2.2 使命和目标 使命 在信息的可用性、安全性和质量方面&#xff0c;满足并超越企业中所有利益相关者的信息要求。 战略目标 &#xff08;1&#xff09;理解企业和所有利益相关者的信息需求。 &#xff08;2&#xff09;获取、存储、保护和确保数据资…

堆的结构及函数接口、堆排序,TopK

本篇内容涉及到二叉树的概念及性质&#xff0c;可参考文章 树和二叉树的概念及性质 文章目录一、堆的概念二、堆的存储结构三、堆的函数接口1. 初始化及销毁2. 打印函数3. 堆的插入4. 堆的删除5. 取堆顶、判空、数据个数四、建堆算法和时间复杂度1. 向上调整建堆2. 向下调整建堆…

CTFshow--web--红包题第二弹

查看源代码&#xff0c;按注释提示&#xff0c;构造参数试试?cmdaa<?php #error_reporting(0); ?> <html lang"zh-CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><meta name&quo…

MATLAB绘制爱心曲线并导出

MATLAB绘制爱心曲线并导出 爱心曲线的表达式&#xff1a; f(x)x2/3e3(π−x2)1/2sin(aπx)f(x)x^{2/3}\frac e 3(\pi-x^2)^{1/2}sin(a\pi x) f(x)x2/33e​(π−x2)1/2sin(aπx) f (x,a)x.^2.^(1/3)exp(1)/3*(pi-x.^2).^(1/2).*sin(a*pi*x); h figure(color,[1 1 1]); set(g…

应用系统与钉钉集成案例及操作步骤

1、准备钉钉应用 1.1、注册钉钉账号 作为钉钉的企业管理员&#xff0c;首先登录钉钉官网&#xff0c;注册一个钉钉账号。 如果已经有账号&#xff0c;则直接使用即可。 钉钉官网&#xff1a;https://www.dingtalk.com/ 1.2、开通企业团队 企业管理员使用账号登录钉钉。 如…

如何限制docker容器使用内存大小

本文介绍如何通过docker运行参数配置限制docker容器可以使用的内存上限。docker容器默认可以使用全部宿主机的所有内存和 swap 分区&#xff0c;比如宿主机的内存是32G&#xff0c;则运行一个docker容器最多可以分配到32G内存&#xff0c;如果启用了多个docker容器&#xff0c;…

CSS实现文本显示两行

效果图 text-overflow: ellipsis;display: -webkit-box;-webkit-line-clamp: 2;-webkit-box-orient: vertical;display: -moz-box;-moz-line-clamp: 2;-moz-box-orient: vertical;overflow-wrap: break-word;word-break: break-all;white-space: normal;overflow: hidden;text-…

SAP ADM100-2.2 SAP系统开启过程中的配置文件

SAP系统的每个实例需要的数据都在文件系统中,包括所有实例都需要访问的全局数据(Globally)和个别实例需要访问的数据。在文件系统汇总,实例需要的数据被包含在usr/sap目录,在这里被进一步组织到子目录。 【注意】:业务数据和相关数据被存储在数据库中,数据库根据不同的制…

【GD32F427开发板试用】三、USB转CAN功能开发与试用总结

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;chenjie 【GD32F427开发板试用】一、环境搭建与freertos移植 【GD32F427开发板试用】二、USB库移植与双USB CDC-ACM功能开发 【GD32F427开发板…

【C++】IO流

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;C语言的输…

04 微服务调用组件Feign

JAVA 项目中如何实现接口调用&#xff1f; 1&#xff09;Httpclient HttpClient 是 Apache Jakarta Common 下的子项目&#xff0c;用来提供高效的、最新的、功能丰富的支持 Http 协议的客户端编程工具包&#xff0c;并且它支持 HTTP 协议最新版本和建议。HttpClient 相比传统…