c++ new 源码学习一下

        之前有一篇文章介绍了 new 的一些用法 c++ new 在指定内存上创建对象,今天结合源码来学习一下 new 更详细的用法。相关的源码:gcc git

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

我们可以在头文件<new>里看到它的原型:

_GLIBCXX_NODISCARD void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc)
  __attribute__((__externally_visible__));

原型上表明此 new 是会抛出异常的,而异常的类型及声明如下:

  /**
   *  @brief  Exception possibly thrown by @c new.
   *  @ingroup exceptions
   *
   *  @c bad_alloc (or classes derived from it) is used to report allocation
   *  errors from the throwing forms of @c new.  */
  class bad_alloc : public exception
  {
  public:
    bad_alloc() throw() { }

#if __cplusplus >= 201103L
    bad_alloc(const bad_alloc&) = default;
    bad_alloc& operator=(const bad_alloc&) = default;
#endif

    // This declaration is not useless:
    // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
    virtual ~bad_alloc() throw();

    // See comment in eh_exception.cc.
    virtual const char* what() const throw();
  };

如果你要自己写异常处理函数,头文件里也有类型说明,必须是这样的函数指针类型:

  /** If you write your own error handler to be called by @c new, it must
   *  be of this type.  */
  typedef void (*new_handler)();

  /// Takes a replacement handler as the argument, returns the
  /// previous handler.
  new_handler set_new_handler(new_handler) throw();

而且还提供了设置异常处理函数的接口,它的返回值是前异常处理函数指针。下面来看一个例子:

#include <iostream>

using namespace std;

void outOfMemory()
{
    cout << "no enough memory" << endl;
}

struct Mem
{
    int array[9999999999999L]; 
};

int main()
{
    set_new_handler(outOfMemory);
    Mem *p = new Mem();

    delete p;

    return 0;
}

结果是这样的,异常函数被循环调用: 

 为什么是这种情况呢?那 new 里到底做了什么呢?我们看一下源码:

_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  void *p;

  /* malloc (0) is unpredictable; avoid it.  */
  if (__builtin_expect (sz == 0, false))
    sz = 1;

  while ((p = malloc (sz)) == 0)
    {
      new_handler handler = std::get_new_handler ();
      if (! handler)
	_GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
    }

  return p;

如果分配不到足够的空间,则异常处理函数会一直被调用,直到能分配到足够的空间。

2,void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) noexcept;

上面的 new 有异常时抛出异常,而这个函数是不会抛出异常的。如:

#include <iostream>

using namespace std;

void outOfMemory()
{
    cout << "no enough memory" << endl;
}

struct Mem
{
    int array[9999999999999L]; 
};

int main()
{
    // set_new_handler(outOfMemory);
    Mem *p = new(std::nothrow) Mem();

    delete p;

    return 0;
}

 带 nothrow 和不带的区别:

 但是如果设置了异常处理函数,即使是 new(std::nothrow) 也会抛出异常,如:

#include <assert.h>
#include <iostream>

using namespace std;

void outOfMemory()
{
    static int count = 0;
    cout << "no enough memory" << endl;

    if(count++ == 10)
    {
        assert(0);
    }
}

struct Mem
{
    int array[9999999999999L]; 
};

int main()
{
    set_new_handler(outOfMemory);
    Mem *p = new(std::nothrow) Mem();

    delete p;

    return 0;
}

 设置的异常处理函数被调用了:

 源码是这样的:

#include <bits/c++config.h>
#include <bits/exception_defines.h>
#include "new"

extern "C" void *malloc (std::size_t);

_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz, const std::nothrow_t&) noexcept
{
  // _GLIBCXX_RESOLVE_LIB_DEFECTS
  // 206. operator new(size_t, nothrow) may become unlinked to ordinary
  // operator new if ordinary version replaced
  __try
    {
      return ::operator new(sz);
    }
  __catch (...)
    {
      // N.B. catch (...) means the process will terminate if operator new(sz)
      // exits with a __forced_unwind exception. The process will print
      // "FATAL: exception not rethrown" to stderr before exiting.
      //
      // If we propagated that exception the process would still terminate
      // (because this function is noexcept) but with a less informative error:
      // "terminate called without active exception".
      return nullptr;
    }
}

这里我们看到不抛出异常的函数是调用了上面那个抛出异常的函数的。所以一旦你设置了异常处理函数,就不能正常抛出异常了,因为只有当 handler = nullptr 时才会抛出异常。

  while ((p = malloc (sz)) == 0)
    {
      new_handler handler = std::get_new_handler ();
      if (! handler)
	_GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
    }

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

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

相关文章

C++11 -- lambda表达式

文章目录 lamaba表达式的引入lambda表达式语法lamabda达式各部分说明捕获列表说明 lamaba表达式底层原理探索 lamaba表达式的引入 在C11之前,如果我们想对自定义类型Goods排序,可以根据姓名,价格,学号按照从大到小或者从小到大的方式排序,可是,这样我们要写额外写6个相关的仿函…

Quest 3初体验,或是苹果MR最大竞争对手

随着苹果MR临近&#xff0c;我们从彭博Mark Gurman了解到更多消息。昨日&#xff0c;Mark Gurman发布了Quest 3上手体验文章&#xff0c;并认为Quest 3可能是苹果MR头显最大的竞争对手。 1&#xff0c;Meta是XR头显领导者 尽管WWDC 23苹果MR将会成为最大的主角&#xff0c;但…

node.js与内置模块

一、目标 能够知道什么是Node.js能够知道Node.js可以做什么能够说出Node.js中的JavaScript的组成部分能够使用fs模块读写操作文件能够使用path模块处理路径能够使用http模块写一个基本的web服务器 二、目录 初始Node.jsfs文件系统模块path路径模块http模块 1.初始Node.js …

macos wireshark 抓取https包

1、启动浏览器 1.1 创建空文件 $ touch /Users/zhujl/Downloads/https/mysslkey.log 2、设置wireshark tls属性&#xff0c;指定tls密钥存储文件 2.1 进入Wireshark Preferfences > Protocols > TLS 属性配置 2.2 勾选上Reassemable TLS records spanning multiple …

设计模式B站学习(一)(java)

这里写目录标题 一、设计模式概述1.1 软件设计模式的产生背景1.2 软件设计模式的概念1.3 学习设计模式的必要性1.4 设计模式分类 二、UML图2.1 类图概述2.2 类图的作用2.3 类图表示法2.3.1 类图表示方法2.3.2 类与类之间关系的表示方法2.3.2.1 关联关系2.3.2.2 聚合关系2.3.2.3…

Selenium的使用

一、基础 1、特点 selenium 是web中基于UI的自动化测试工具&#xff0c;它支持多平台、多语言、多浏览器&#xff0c;还有丰富的API。 2、原理 自动化脚本代码会创建一个http请求发送给浏览器驱动进行解析&#xff0c;浏览器驱动会操控浏览器执行测试&#xff0c;浏览器接着…

ffmpeg编译成wasm

最近在看ffmpeg的源码 https://ffmpeg.xianwaizhiyin.net/ffplay/ https://crifan.github.io/media_process_ffmpeg/website/audio_process/ 做个可运行的例子 代码在找了一堆&#xff0c;可用的版本放在这 https://github.com/killinux/ffmpeg_wasm_demo 先把ffmpeg 编译成 …

内蒙古自治区出台加快充换电基础设施建设实施方案

摘要&#xff1a;为深入贯彻落实《国务院办公厅关于印发新能源汽车产业发展规划&#xff08;2021—2035年&#xff09;的通知》&#xff08;国办发 ﹝2020﹞39号&#xff09;、《国家发展改革委等部门关于进一步提升电动汽车充电基础设施服务保障能力的实施意见》&#xff08;发…

Unity——在C#中调用C++动态链接库(DLL)

一、创建C动态链接库&#xff08;DLL&#xff09; 1、新建C空项目 打开VS&#xff0c;新建一个C空项目&#xff0c;自命名项目名称与位置。 2、配置项目属性为动态链接库 右键项目&#xff0c;点击属性&#xff0c;打开项目属性页&#xff0c;将常规中的配置类型改为动态库&…

电力电子技术的论文

电力电子技术的论文范文一&#xff1a;Matlab电力电子技术应用 【文章摘要】信息技术的快速发展推动许多学科进一步完善&#xff0c;以电力电子技术为例&#xff0c;其本身具有较强的理论性、实践性等特征&#xff0c;涉及的波形图、电路图也较多&#xff0c;相关设计人员需掌握…

【C++初阶】C++STL详解(一)—— string类

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 CSTL详解&#xff08;一…

新华三的网络脉动:为AI泵血,向产业奔流

AI大模型作为最新的通用技术&#xff0c;今年以来&#xff0c;发展如火如荼。也有很多从业者和专家注意到&#xff0c;AI模型训练和应用过程中&#xff0c;需要优先考虑网络的升级与适配。 如果说数据中心、算力集群是AI的“心脏”&#xff0c;那么网络就犹如AI的“动脉”&…

综合指挥调度系统行业分类汇总

综合指挥调度系统是将语音、视频、GIS进行高度融合&#xff0c;构建“平战结合”的指挥调度模式&#xff0c;既满足平时的应急培训、日常通信、会议会商等要求&#xff0c;也能够应对战时的应急指挥、应急救援、应急决策等需求&#xff0c;达到统一指挥、联合行动的目的&#x…

ArduPilot之H743+BMI270x2+First Normal Takeoff

ArduPilot之H743BMI270x2First Normal Takeoff 1. 源由2. 正常起飞3. 问题汇总3.1 机架构型3.2 IMU对齐3.3 接收机3.4 GPS3.5 VTX3.6 电调3.7 PID 4. 总结5. 参考资料6. 附录6.1 补充AcroTrainer视频6.2 补充Acro视频 1. 源由 鉴于目前该飞控板子在ArduPilot开源社区尚未得到官…

15.2:分金条的最小代价

一块金条切成两半&#xff0c;是需要花费和长度数值一样的铜板 比如长度为20的金条&#xff0c;不管怎么切都要花费20个铜板&#xff0c;一群人想整分整块金条&#xff0c;怎么分最省铜板? 例如&#xff0c;给定数组{10,20,30}&#xff0c;代表一共三个人&#xff0c;整块金条…

笔试强训错题总结(一)

笔试强训错题总结 文章目录 笔试强训错题总结选择题编程题连续最大和不要二最近公共祖先最大连续的bit数幸运的袋子手套 选择题 以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main(void) {printf("%s , %5.3s\n", "computer&q…

chatgpt赋能python:Python反转输出正整数-让计算更简单

Python反转输出正整数-让计算更简单 Python是一种高级编程语言&#xff0c;除了可以完成各种任务&#xff0c;还可以反转输出正整数。在本篇SEO文章中&#xff0c;我将介绍如何使用Python编程语言反转输出正整数&#xff0c;并且展现了这个方法是如何简化计算。 什么是Python…

linux网络初探

linux网络 1.1查看本机ip IP地址 IP地址网络地址主机地址&#xff0c;网络地址&#xff08;网络号&#xff09;相同的主机为本地网络中的主机&#xff0c;可以直接相互通信&#xff0c;而网络地址不同的主机为远程网络中的主机&#xff0c;相互通信必须通过本地网关&#xf…

重学迭代器和生成器

重学迭代器和生成器 之前在 JavaScript 高级程序设计第 7 章 迭代器和生成器 学习笔记 其实包含过 iterator 和 generator 的学习笔记&#xff0c;不过依旧温故而知新&#xff0c;有了一些实际上手的经验后重新再回滚一边会有比较深刻的理解&#xff0c;而不是只是 cv 书上的内…

python+pytest接口自动化之HTTP协议基础

目录 HTTP协议简介 HTTP协议特点 HTTP接口请求方法 HTTP与HTTPS区别 HTTP与TCP/IP区别 HTTP请求过程 总结 HTTP协议简介 HTTP 即 HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09;&#xff0c;是互联网上应用最为广泛的一种网络协议。所有的 WWW 文件…