尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
11. 类和动态内存分配
类和动态内存分配动态内存和类在类中使用 new 和 delete 来动态管理内存可以让程序在运行时而非编译时决定内存分配。在类构造函数中使用 new需要额外执行一系列步骤扩展析构函数、编写额外的类方法来帮助正确完成初始化和赋值。否则会导致严重问题。#include cstring #include strngbad.h using std::cout; ​ // 初始化静态成员 int StringBad::num_strings 0; ​ // 从 C 风格字符串构造 StringBad StringBad::StringBad(const char * s) { len std::strlen(s); str new char[len 1]; // 分配内存 std::strcpy(str, s); // 复制字符串 num_strings; // 对象计数 1 cout num_strings : \ str \ object created\n; } ​ // 默认构造函数 StringBad::StringBad() { len 4; str new char[4]; std::strcpy(str, C); num_strings; cout num_strings : \ str \ default object created\n; } ​ // 析构函数 StringBad::~StringBad() { cout \ str \ object deleted, ; --num_strings; cout num_strings left\n; delete [] str; // 释放动态分配的内存 } ​ std::ostream operator(std::ostream os, const StringBad st) { os st.str; return os; }使用赋值运算符的时候编译器会使用默认复制构造函数会产生浅拷贝导致程序调用两次析构函数产生未定义行为。特殊成员函数何时自动生成默认行为默认构造函数没有定义任何构造函数不执行任何操作默认析构函数没有定义析构函数不执行任何操作复制构造函数程序使用对象的方式需要时逐成员复制浅拷贝赋值运算符程序使用对象的方式需要时逐成员复制浅拷贝地址运算符程序使用对象的方式需要时返回this指针C11 还新增了移动构造函数和移动赋值运算符第18章用于支持移动语义。默认构造函数如果没有提供任何构造函数编译器会生成一个隐式默认构造函数Klunk::Klunk() { } // 什么都不做但是如果定义了任意一个构造函数编辑器就不会生成默认构造函数了。默认构造函数的定义方式// 方式一无参构造函数 Klunk() { klunk_ct 0; } ​ // 方式二所有参数都有默认值 Klunk(int n 0) { klunk_ct n; }复制构造函数Class_name(const Class_name );复制构造函数的调用时机。显式初始化新对象为现有对象函数按值传递对象函数按值返回对象编译器生成临时对象。按值传递会调用复制构造函数因此对于大型对象应优先使用按引用传递以节省时间和内存。默认构造函数默认浅拷贝。在构造函数中使用new规则析构函数必须使用deletenew和delete匹配。new—deletenew[]—delete[]必须自定义复制构造函数深拷贝。必须自定义赋值运算符。必须检测自我赋值对象的返回方式返回指向对象的引用返回指向对象本身返回const对象返回指向const对象引用。可以提高效率避免调用赋值构造函数// 版本1按值返回调用复制构造函数效率较低 Vector Max(const Vector v1, const Vector v2) { if (v1.magval() v2.magval()) return v1; else return v2; } ​ // 版本2返回 const 引用效率更高 const Vector Max(const Vector v1, const Vector v2) { if (v1.magval() v2.magval()) return v1; // 返回引用指向调用者已存在的对象 else return v2; }返回非const对象的引用两种场景场景一赋值运算符考虑到调用者可能对其进行修改如(s2 s1).some_method()。选择*this。String String::operator(const String st) { if (this st) return *this; delete [] str; // ... 复制操作 ... return *this; // 返回非 const 引用 }场景二operator 与 cout目的支持链式输出如 cout s1 is coming!;。ostream operator(ostream os, const String st) { os st.str; return os; // 必须返回 ostream }由于ostream没有公有的复制构造函数返回引用支持链式调用。为什么不能使用const引用ostream内部对象都是非const对象一个 const 对象无法绑定到非 const 引用参数。输出流对象在输出过程中会改变内部状态比如设置错误位、刷新缓冲区等使用对象的指针使用new初始化对象的语法// 使用复制构造函数 String * favorite new String(sayings[choice]); ​ // 使用默认构造函数 String * gleep new String; ​ // 使用带参构造函数 String * glop new String(my my my);对定位 new 创建的对象使用 delete 是错误的因为 delete 只应用于常规 new 分配的地址必须显式调用析构函数。常规new运算符和定位new运算符常规 new“分配内存 调用构造函数”。如果内存不够它会自己去堆上找。定位 newPlacement new“只调用构造函数”。它不管内存从哪来你已经提供好了地址它就在那个地址上构造对象// 常规 new String* p1 new String(Hello); ​ // 定位 new多了一个括号参数传入地址 #include new // 必须包含头文件 char buffer[100]; // 你准备好的“空地”栈上 String* p2 new (buffer) String(World); // 在 buffer 这块内存上构造 String复习重载 可以使用友元函数或者通过公有函数暴露接口写一个全局函数推荐返回值使用ostream 非const引用转换函数一个参数的构造函数推荐使用explicit禁止隐式类型转换。赋值运算符必须检查自我复制。队列模拟#ifndef QUEUE_H_ #define QUEUE_H_ ​ // 客户类模拟队列中存储的数据类型 class Customer { private: long arrive; // 到达时间分钟 int processtime; // 服务所需时间1~3分钟 public: Customer() : arrive(0), processtime(0) {} void set(long when); long when() const { return arrive; } int ptime() const { return processtime; } }; ​ typedef Customer Item; // 队列中的项目类型 ​ // 队列类 class Queue { private: // 嵌套结构链表节点作用域限定在类内部 struct Node { Item item; struct Node * next; }; ​ enum { Q_SIZE 10 }; // 默认队列容量 ​ // 数据成员 Node * front; // 指向队首 Node * rear; // 指向队尾 int items; // 当前元素个数 const int qsize; // 最大容量const成员必须用初始化列表 ​ // 禁止复制私有化防止浅拷贝导致的链表共享问题 Queue(const Queue q) : qsize(0) { } Queue operator(const Queue q) { return *this; } ​ public: // 构造函数指定容量默认10 Queue(int qs Q_SIZE); // 析构函数释放所有节点 ~Queue(); // 状态检查 bool isempty() const; bool isfull() const; int queuecount() const; ​ // 核心操作 bool enqueue(const Item item); // 入队队尾添加 bool dequeue(Item item); // 出队队首移除 }; ​ #endif#include queue.h #include cstdlib // 用于 rand() ​ // ---------- Customer 类方法 ---------- void Customer::set(long when) { processtime std::rand() % 3 1; // 随机生成 1~3 分钟的服务时间 arrive when; } ​ // ---------- Queue 类方法 ---------- ​ // 构造函数初始化空队列 Queue::Queue(int qs) : qsize(qs), front(nullptr), rear(nullptr), items(0) { // 函数体为空所有初始化已在初始化列表中完成 } ​ // 析构函数删除所有剩余节点 Queue::~Queue() { Node * temp; while (front ! nullptr) { temp front; // 保存当前队首 front front-next; // 移动队首指针 delete temp; // 删除旧节点 } } ​ // 检查队列是否为空 bool Queue::isempty() const { return items 0; } ​ // 检查队列是否已满 bool Queue::isfull() const { return items qsize; } ​ // 返回当前队列中的元素个数 int Queue::queuecount() const { return items; } ​ // 入队在队尾添加元素 bool Queue::enqueue(const Item item) { if (isfull()) return false; ​ // 创建新节点 Node * add new Node; add-item item; // 复制数据 add-next nullptr; // 新节点将成为队尾next 指向空 ​ items; // 计数加1 ​ // 链接到队列中 if (front nullptr) // 如果队列为空 front add; else rear-next add; // 否则接到当前队尾后面 ​ rear add; // 更新队尾指针 return true; } ​ // 出队从队首移除元素数据存入引用参数 bool Queue::dequeue(Item item) { if (front nullptr) return false; ​ item front-item; // 取出队首数据 items--; // 计数减1 ​ Node * temp front; // 保存旧队首地址 front front-next; // 移动队首指针 delete temp; // 释放旧节点 ​ if (items 0) // 如果队列已空 rear nullptr; ​ return true; }
RELATED

相关推荐

车载以太网(0)

车载以太网(0)

专栏更新说明从今天开始我将不定期的更新车载以太网的相关知识和资料,以及我在工作中遇到问题的一些解决方案和思考路径。我本身工作比较忙,所以希望自己能每周更新至少一篇到两篇专栏文章,希望可以对刚进入车载以太网的同学或者在行业中但是…

📅 2026/9/25 2:16:50
专业二手车网站建设方案解析:如何通过优化内容提升客户信任度与转化率

专业二手车网站建设方案解析:如何通过优化内容提升客户信任度与转化率

做二手车这一行,大家心里都跟明镜似的。这年头,车是好车,但人心是不稳的。顾客怕买到事故车、泡水车、调表车,咱们商家怕遇到难缠的投诉、无理的砍价,最后搞得两败俱伤。在这种大环境下,一个靠谱的二手车网站,就不再仅仅是一个展示车辆的网页了,它更像是一扇窗,一扇门…

📅 2026/9/2 12:51:22
3D打印行业趋势:设备升级、材料突破与市场应用

3D打印行业趋势:设备升级、材料突破与市场应用

1. 3D打印行业动态速览:从设备迭代到市场格局演变今天早上刷行业新闻时,突然被三条重磅消息刷屏:陕西又上马了新的增材制造项目、Stratasys发布2025年财务预测、创想三维推出Ender-3系列第四代机型。这三个看似独立的事件,恰好构成…

📅 2026/9/1 3:31:32
MORE NEWS

更多资讯

📰

Kerberos委派攻击全解析:从非约束委派到RBCD与Spooler触发

一次授权内网测试里,我在客户现场盯着一台普通文件服务器看了很久。目标域有三千多用户,域控制器权限划分得比较谨慎,常规漏洞没抓到什么机会。后面想起来翻了一下LDAP里的委派配置,发现这台文件服务器竟然开了非约束委派&#xf…

📰

无需上传IPA的在线砸壳工具dumpipa.com实测与原理分析

1. 砸壳这件事,到底在解决什么问题做iOS逆向或者安全研究的朋友,对“砸壳”这个词肯定不陌生。简单说,App Store下载的IPA包是经过加密的,可执行文件被一层“壳”包住,直接拖进IDA或者Hopper看,全是乱码。你…

📰

4.1存储器概述

1.存储器概述2.存储器的分类 2.1:存储器的分类2.2:几种常见的存储器3.存储器的性能指标 3.1:存储容量3.1:存取速度4.存储系统的层次结构5.主存的基本结构6.主存中数据的存放 6.1:机器字长与存储字长的区别6.2:地址访问模式6.3&…

📰

OpenClaw Windows 一键部署:虾壳云定制优化包配 TaoToken 省去环境配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Atlas 300V 24G部署YOLO实战:模型转换、环境搭建与性能调优

1. 从热搜说起:Atlas 300V 24G到底是不是运算加速卡最近后台收到不少朋友在问同一个问题:“Atlas 300V 24G是运算加速卡吗?”说实话,这个问题我当年第一次接触华为Atlas产品线时也困惑过,因为市面上叫“加速卡”的东西…

📰

ESPnet2 中 LibriSpeech-100 的 ASR 配方全解析:从 E-Branchformer 到多任务解码实践

人工智能语音音频深度学习NLP 【免费下载链接】espnet End-to-End Speech Processing Toolkit 项目地址: https://gitcode.com/gh_mirrors/es/espnet 点击查看 免费下载 导读 本文基于 ESPnet 开源语音处理工具包的 LibriSpeech-100 数据集 ASR 配方(e…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬