当前位置: 首页 > news >正文

【C++ techniques】要求/禁止/判断—对象产生于堆中

  • 有时候我们想让某种对象具有“自杀”的能力,所以我们必须要求对象存在堆中,以便我们调用delete this;
  • 另一些时候,我们要求拥有某种确定性,保证某一些类型绝不会发生内存泄漏,原因是没有任何一个该类型的对象从堆中分配出来;堆空间非常宝贵,所以我们要对象全为栈对象,必须禁止对象产生于堆中。

要求对象产生于堆中(Heap-Based Objects)

  • 为限制对象产生于heap,我们需阻止clients不得使用new以外的方法产生对象;
  • non-heap objects会在其定义点自动构造,并在其寿命结束时自动析构,所以只需让那些被隐式调用的构造函数和析构函数不合法;
  • 比较好的方法是让destructor成为private,而constructors仍为public;
  • 如此一来,你可以导入一个pseudo destructor函数,用来调用真正的destructor。Clients则调用pseudo-destructor来销毁它们产生的对象。

例如,假设我们希望确保“表现无限精度”的数值对象只能诞生于heap之中:

class UPNumber
{
public:UPNumber();UPNumber(int initValue);UPNumber(double initValue);UPNumber(const UPNumber& rhs);private:~UPNumber();//dtor位于private内
};
//Clients于是应该这么写:
UPNumber n; //错误!(虽然合法,但当n的dtor被隐式调用,就不合法了)UPNumber* p = new UPNumber; //良好
...
delete p;	//错误!企图调用private destructor
p->destroy(); //良好
  • 只要限制destructor和constructors的运用,便可阻止non-heap objects的诞生,但是,它妨碍了继承和内含:
class UPNumber{...};	//将dtor或ctor声明为private
class NonNegativeUPNumber:public UPNumber{...};//错误!dtor或ctors无法通过编译class Asset
{
private:UPNumber value;		//错误!dtor或ctors无法通过编译...
};

解决:

  1. 令UPNumber的destructor成为protected(并仍保持其constructors为public),便可以解决继承问题;
  2. “必须内含UPNumber对象”之classes可以修改为“内含一个指针,指向UPNumer”对象:
class UPNumber{...};	//注意将dtor声明为protected
class NonNegativeUPNumber:public UPNumber{...}; //derived classes可以调用protected membersclass Asset
{
public:Asset(int initValue);~Asset();...
private:UPNumber* value;		
};Asset::Asset(int initvalue):value(new UPNumber(initValue))
{...
}Asset::~Asset()
{value->destroy();
}

判断某对象是否位于堆内

abstract mixin base class(抽象混合式基类):

  • abstract base class是一个不能被实例化的基类;
  • mixin class则提供一组定义完好的能力,能够与其派生类所可能提供的其他任何能力兼容。

我们可以形成一个所谓的抽象混合式基类,用来为派生类提供“判断某指针是否以operator new分配出来的能力:

class HeapTracked //mixin class;追踪并记录被operator new返回的指针
{
public:class MissingAddress{};virtual ~HeapTracked() = 0;static void* operator new(size_t size);//负责分配内存内存并将条目加入list内static void operator delete(void* ptr);//负责释放内存并从list身上移除条目bool isOnHeap() const; //决定某对象的地址是否在list内private:typedef const void* RawAddress;static list<RawAddress> addresses; //list记录所有由operator new返回的指针
};
//HeapTracked的完整实现内容:list<RawAddress> HeapTracked::addresses;HeapTracked::~HeapTracked{}void* HeapTracked::operator new(size_t size)
{void* memPtr = ::operator new(size);addresses.push_back(memPtr);return memPtr;
}void HeapTracked::operator delete(void* ptr)
{list<RawAddress>::iterator it  = find(addresses.begin(),addresses.end(),ptr);if(it != addresses.end()){address.erase(it);::operator delete(ptr);}else{throw MissingAddress();}
}bool HeapTracked::isOnHeap() const
{//取得一个指针,指向*this所占内存的起始处const void* rawAddress = dynamic_cast<const void*>(this);list<RawAddress>::iterator it = find(address.begin(),address.end(),rawAddress);return it != address.end();
}

禁止对象产生于堆中

一般而言有3种可能:

  1. 对象被直接实例化;
  2. 对象被实例化为派生类对象内的“基类”成分;
  3. 对象被内嵌于其他对象之中。

欲阻止clients直接将对象实例化于heap之中,你可以让client无法调用new:定义operator new,将其声明为private

如果不希望clients将UPNumber对象产生于堆内:

class UPNumber
{
private:static void* operator new(size_t size);static void operator delete(void* ptr);...
};

如果要禁止产生“UPNumer对象所组成的数组”,可以将operator new[]operator delete[]声明为private。

将operator new声明为private,往往也会妨碍UNumber对象被实例化为heap-based derived class objects的“base class成分”,因为operator new和operator delete会被继承,所以如果这些函数不在derived class声明为public,derived class继承的便是base(s)所声明的private版本:

class UPNumber{...};
class NonNegativeUPNumber:  //假设此class未声明operator newpublic UPNumber
{...
};NonNegativeUPNumber n1;				
static NonNegativeUPNumber n2;		
NonNegativeUPNumber* p = new NonNegativeUPNumber;//错误!企图调用private operator new

如果derived class声明一个属于自己的operator new(且为public),类似于,当我们企图分配一个“内含UPNumber对象”的对象,“UNPumber的operator new乃为private“不会带来什么影响:

class Asset
{
public:Asset(int initValue);...
private:UPNumber value;
};Asset* pa = new Asset(100); //没问题,调用的是//Asset::operator new或//::operator new而非UPNumber::operator new

我们曾经希望“如果一个UPNumber对象被构造于heap以外,那么就在UPNumber constructor内抛出异常”,这次我们希望“如果对象被产生于heap内的话,就抛出一个异常”。然而,就像没有任何根据移植性的做法可以判断某地址是否位于heap内一样,我们也没有根据移植性的做法可以判断它是否不在heap内。

相关文章:

【C++ techniques】要求/禁止/判断—对象产生于堆中

有时候我们想让某种对象具有“自杀”的能力&#xff0c;所以我们必须要求对象存在堆中&#xff0c;以便我们调用delete this&#xff1b;另一些时候&#xff0c;我们要求拥有某种确定性&#xff0c;保证某一些类型绝不会发生内存泄漏&#xff0c;原因是没有任何一个该类型的对象…...

吃鸡高手亲授:玩转绝地求生,分享顶级游戏干货!

绝地求生&#xff08;PUBG&#xff09;自上线以来&#xff0c;成为了全球热门游戏。作为吃鸡行家&#xff0c;我将分享一些独家技巧和干货&#xff0c;帮助您提高游戏战斗力&#xff0c;享受顶级游戏作战体验&#xff01; 首先&#xff0c;让我们谈一谈战斗力升级。想要在吃鸡游…...

Vue中如何进行自定义图表与可视化图形设计

Vue中如何进行自定义图表与可视化图形设计 在现代Web应用程序开发中&#xff0c;数据可视化图表和图形设计是至关重要的一部分。Vue.js是一个流行的JavaScript框架&#xff0c;它提供了强大的工具来构建交互性强大的用户界面。本文将探讨如何在Vue.js中进行自定义图表和可视化…...

学信息系统项目管理师第4版系列19_质量管理

1. 公差 1.1. 质量测量中公差是测量指标的可允许变动范围&#xff0c;而不是实际测量值与预期值的差 1.1.1. 【高22下选35】 1.2. 结果的的可接受范围 2. 控制界限 2.1. 统计意义上稳定的过程或过程绩效的普通偏差的边界 3. 3版 3.1. 质量控制新七工具 3.1.1. 【高19下…...

react库的基础学习

React介绍 React.js是前端三大新框架&#xff1a;Angular.js、React.js、Vue.js之一&#xff0c;这三大新框架的很多理念是相同的&#xff0c;但是也有各自的特点。 React起源于Facebook的内部项目&#xff0c;因为该公司对市场上所有 JavaScript MVC 框架&#xff0c;都不满…...

FFmpeg 基础模块:容器相关的 API 操作

目录 AVFormat 模块 AVFormat 前处理部分 AVFormat 读写处理部分 小结 思考 FFmpeg 目录中包含了 FFmpeg 库代码目录、构建工程目录、自测子系统目录等&#xff0c;具体内容如下&#xff1a; 现在你知道 FFmpeg 的源代码目录中都包含了哪些内容&#xff0c;在之后使用 FFm…...

SpringMVC+统一表现层返回值+异常处理器

一、统一表现层返回值 根据我们不同的处理方法&#xff0c;返回的数据格式都会不同&#xff0c;例如添加只返回true|false&#xff0c;删除同理&#xff0c;而查询却返回数据。 Result类 为此我们封装一个result类来用于表现层的返回。 public class Result {//描述统一格式…...

2023年地理信息系统与遥感专业就业前景与升学高校排名选择

活动地址&#xff1a;毕业季进击的技术er 地理信息系统&#xff08;GIS&#xff0c;Geographic Information System&#xff09;&#xff0c;又称“地理信息科学”&#xff08;Geographic Information Science&#xff09;&#xff0c;是一种具有信息系统空间专业形式的数据管理…...

第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第二节 - Python 字符串—Python 字符串 len()的语法)

Python len() 函数返回字符串的长度。 目录 Python len() 语法 Python len() 示例 示例 1:带有元组和字符串的 Len() 函数...

ubuntu22.04使用共享文件设置

从ubuntu20.04开始&#xff0c;设置共享文件就很麻烦 第一步&#xff1a; 安装samba&#xff1a; sudo apt install samba第二步; 创建一个共享文件夹 我以桌面Desktop为例子 第三步&#xff1a; 设置密码&#xff1a; sudo smbpasswd -a ygc第四步&#xff1a; sudo vim …...

pycharm配置python3.8版本专门用于undecteded_chromedriver测试

pycharm配置python3.8版本专门用于undecteded_chromedriver测试 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://pay.xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 一、Pycharm及python环境的配置 1.安装python-3.8.7rc1-amd64.e…...

基于SpringBoot的民宿在线预定平台

目录 前言 一、技术栈 二、系统功能介绍 用户信息管理 民宿信息管理 民宿资讯管理 民宿分类管理 用户注册 民宿信息 我的订单 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实…...

CTFHUB SSRF

目录 web351 ​编辑 web352 web353 web354 sudo.cc 代表 127 web355 host长度 web356 web357 DNS 重定向 web358 bypass web359 mysql ssrf web360 web351 POST查看 flag.php即可 web352 <?php error_reporting(0); highlight_file(__FILE__); $url$_…...

FreeRTOS入门教程(队列详细使用示例)

文章目录 前言一、队列基本使用二、如何分辨数据源三、传输大块数据总结 前言 上篇文章我们已经讲解了队列的概念和队列相关的API函数&#xff0c;那么本篇文章的话就开始带大家来学习使用队列。 一、队列基本使用 这个例子将会创建三个任务&#xff0c;其中两个任务用来发送…...

【Kafka专题】Kafka收发消息核心参数详解

目录 前置知识课程内容一、从基础的客户端说起&#xff08;Java代码集成使用&#xff09;1.1 消息发送者源码示例1.2 消息消费者源码示例1.3 客户端使用小总结 *二、从客户端属性来梳理客户端工作机制*2.1 消费者分组消费机制2.2 生产者拦截器机制2.3 消息序列化机制2.4 消息分…...

matlab 使用激光雷达检测、分类和跟踪车辆

目录 1、算法概述2、加载数据3、地平面分割4、语义分割5、聚类和边界盒拟合6、可视化设置7、循环遍历数据8、面向跟踪的包围盒9、 总结10、 支持功能11、 参考</...

代码随想录训练营二刷第四十八天 | 139.单词拆分 背包问题总结

代码随想录训练营二刷第四十八天 | 139.单词拆分 背包问题总结 一、139.单词拆分 题目链接&#xff1a;https://leetcode.cn/problems/word-break/ 思路&#xff1a;单词拼字符串&#xff0c;完全背包。定义dp[i]&#xff0c;为true表示可以拆分为一或多个单词。可能会出现ab…...

【数据挖掘】2017年 Quiz 1-3 整理 带答案

目录 Quiz 1Quiz 2Quiz 3Quiz 1 Answer Problems 1-2 based on the following training set, where A , B , C A, B, C A,B,</...

吃鸡高手必备工具大揭秘!提高战斗力,分享干货,一站满足!

大家好&#xff01;你是否想提高吃鸡游戏的战斗力&#xff0c;分享顶级的游戏作战干货&#xff0c;方便进行吃鸡作图和查询装备皮肤库存&#xff1f;是否也担心被骗&#xff0c;希望查询游戏账号是否在黑名单上&#xff0c;或者查询失信人和VAC封禁情况&#xff1f;在这段视频中…...

集群化环境前置准备

目录 部署 1. 配置多台Linux虚拟机 1.1 首先&#xff0c;关机当前CentOS系统虚拟机&#xff08;可以使用root用户执行init 0来快速关 机&#xff09; 1.2 新建文件夹 1.3 克隆 1.4 同样的操作克隆出&#xff1a;node2和node3 1.5 开启node1&#xff0c;修改主机名为node1&…...

Next.js App Router与React Server Components实战:构建高性能Hacker News克隆

1. 项目概述&#xff1a;一个基于 Next.js App Router 与 React Server Components 的 Hacker News 克隆 如果你和我一样&#xff0c;在过去几年里一直在用 Next.js 的 Pages Router 构建应用&#xff0c;那么当 App Router 和 React Server Components 这两个概念一起出现时&…...

联想拯救者15ISK加装NVMe SSD实战:从硬件兼容到系统部署的避坑指南

1. 联想拯救者15ISK加装NVMe SSD前的准备工作 我手上这台联想拯救者15ISK已经陪伴我征战了五年多&#xff0c;最近明显感觉到系统响应变慢&#xff0c;游戏加载时间变长。经过一番排查&#xff0c;发现瓶颈主要出在机械硬盘上。于是决定给它加装一块NVMe SSD&#xff0c;让老战…...

copaw1.1:非侵入式调试与性能分析工具实战指南

1. 项目概述与核心价值最近在折腾一个挺有意思的开源项目&#xff0c;叫copaw1.1&#xff0c;是mattchentj-debug这个仓库下的一个工具。别看它名字有点抽象&#xff0c;其实它是一个专门用来辅助调试和性能分析的“瑞士军刀”。简单来说&#xff0c;它能在你运行程序的时候&am…...

大模型多格式量化训练技术解析与应用实践

1. 多格式量化训练技术解析在大语言模型部署实践中&#xff0c;量化技术已经成为平衡计算效率和模型性能的关键手段。传统量化方案通常需要为每种目标精度单独训练和存储模型&#xff0c;这在资源受限的边缘设备上会带来显著的存储和管理开销。多格式量化训练(Multi-format QAT…...

Swift集成OllamaKit:本地大模型原生应用开发实战指南

1. 项目概述&#xff1a;当大模型遇上原生应用最近在折腾一个很有意思的东西&#xff0c;想给手头的 macOS 应用加上一点“智能”。不是那种简单的网络请求&#xff0c;而是希望它能像 ChatGPT 那样&#xff0c;在本地就能理解我的指令、生成文本&#xff0c;甚至进行简单的推理…...

mitojs高级配置与Hook机制:如何实现高度定制化监控

mitojs高级配置与Hook机制&#xff1a;如何实现高度定制化监控 【免费下载链接】monitor &#x1f440; 一款轻量级的收集页面的用户点击行为、路由跳转、接口报错、代码报错、页面性能并上报服务端的SDK 项目地址: https://gitcode.com/gh_mirrors/mo/monitor 在当今We…...

Payum实战案例:构建支持多种支付方式的电商平台完整指南 [特殊字符]

Payum实战案例&#xff1a;构建支持多种支付方式的电商平台完整指南 &#x1f680; 【免费下载链接】Payum PHP Payment processing library. It offers everything you need to work with payments: Credit card & offsite purchasing, subscriptions, payouts etc. 项目…...

有一种同事,领导再信任也要小心提防

◆你好。 职场上有这么一类人&#xff0c;他们精于伪装&#xff0c;表面上能力出众、忠心耿耿&#xff0c;实则暗地里拉帮结派、打压异己&#xff0c;甚至一步步架空领导。 这种人最可怕的地方在于&#xff0c;他们往往深得领导信任&#xff0c;成为团队里的"红人"。…...

前端自定义光标系统:从原理到工程实践

1. 项目概述&#xff1a;一个可深度定制的网页光标系统最近在做一个前端项目时&#xff0c;遇到了一个挺有意思的需求&#xff1a;用户希望网页上的光标不仅仅是默认的箭头或小手&#xff0c;而是能根据不同的交互状态、页面区域甚至用户偏好&#xff0c;动态切换成各种自定义的…...

Weaviate官方示例库全解析:从向量数据库入门到AI应用实战

1. 项目概述&#xff1a;一个向量数据库的“游乐场”如果你最近在折腾大语言模型应用&#xff0c;或者想给自己的数据加上一个智能的“记忆大脑”&#xff0c;那你大概率已经听说过向量数据库了。在众多选择中&#xff0c;Weaviate 以其开源、易用和强大的功能&#xff0c;成为…...