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

c++primier第十二章类和动态内存

本章内容包括:

  • 对类成员使用动态内存分配
  • 隐式和显式地复制构造函数
  • 隐式和显式地重载赋值操作符
  • 在构造函数中使用new所必须完成的工作
  • 使用静态类成员

  • 将布局new操作符用于对象
  • 使用指向对象的指针
  • 实现队列抽象数据类型(ADT)

 动态内存和类

复习范例和静态类成员

首先设计一个 StringBad类,然后设计一个功能稍强的 String类。

StringBad 和 String 类对象将包含一个字符串指针和一个表示字符串长度的值。这里使用 StingBad 和String 类,主要是为了深入了解 new、delete 和静态类成员的工作原理。因此,构造函数和析构函数调用时将显示一些消息,以便读者能够按照提示来完成操作。

对这个声明,需要注意的有两点。首先,它使用char指针(而不是char 数组)来表示姓名。这意味着类声明没有为字符串本身分配存储空间,而是在构造函数中使用new来为字符串分配空间。这避免了在类声明中预先定义字符串的长度。

strngbad.h

#include <iostream>
#ifndef STRNGBAD_H_
#define STRNGBAD_H_class StringBad
{
private:char *str;int len;static int num_strings;public:StringBad(const char *s);StringBad();~StringBad(); // destructor// friend functionfriend std::ostream &operator<<(std::ostream &os, const StringBad &st);
};
#endif

strngbad.cpp

#include <cstring>
#include "strngbad.h"
using std::cout;// initialjzing static class member
int StringBad::num_strings = 0;
// class methods
// construct StringBad fromC string
StringBad::StringBad(const char *s)
{len = std::strlen(s);str = new char[len + 1];std::strcpy(str, s);num_strings++;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;
}

这条语句将静态成员num stings的值初始化为0。请注意,不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。

初始化是在方法文件中,而不是在类声明文件中进行的,这是因为类声明位于头文件中,程序可能将头文件包括在其他几个文件中。如果在头文件中进行初始化,将出现多个初始化语句副本,从而引发错误。

析构函数首先指出自己何时被调用。这部分包含了丰富的信息,但并不是必不可少的。不过,delete语句却是至关重要的。str 成员指向new 分配的内存。当StringBad 对象过期时,str 指针也将过期。但 str指向的内存仍被分配,除非使用deete 将其释放。删除对象可以释放对象本身占用的内存,但并不能自动释放属于对象成员的指针指向的内存。因此,必须使用析构函数。在析构函数中使用delete 语句可确保对象过期时,由构造函数使用 new分配的内存被释放。

vegnews.cpp

#include <iostream>
using std::cout;
#include "strngbad.h"void callme1(StringBad &); // pass by reference
void callme2(StringBad);   // pass by value
int main()
{using std::endl;StringBad headlinel("Celery stalks at Midnight");StringBad headline2("Lettuce Prey");StringBad sports("Spinach Leaves Bowl for Dollars");cout << "headlinel:" << headlinel << endl;cout << "headline2:" << headline2 << endl;cout << "sports:" << sports << endl;callme1(headlinel);cout << "headlinel:" << headlinel << endl;callme2(headline2);cout << "headline2:" << headline2 << endl;cout << "Initialize one object to another:\n";StringBad sailor = sports;cout << "sailor:" << sailor << endl;cout << "Assign one object to another:\n";StringBad knot;knot = headlinel;cout << "knot: " << knot << endl;cout << " End of main()\n ";return 0;
}void callme1(StringBad &rsb)
{cout << "String passed by reference: \n";cout << "    \"" << rsb << "\"\n";
}void callme2(StringBad sb)
{cout << "String passed by value: \n";cout << sb << "\"\n";
}

提前中断

程序说明

callme1()按引用传递没有发生问题

callme2()按值传递发生问题

首先,将 headline2作为函数参数来传递从而导致析构函数被调用。其次,虽然按值传递可以防止原始参数被修改,但实际上函数已使原始字符串无法识别,导致显示一些非标准字符(显示的具体内存取决于内存中包含的内容)。

当您使用一个对象来初始化另一个对象时,编译器将自动生成上述构造函数(称为复制构造函数,因为它创建对象的一个副本)。自动生成的构造函数不知道需要更新静态变量num_strings,因此会将计数方案搞乱。实际上,这个例子说明的所有问题都是由编译器自动生成的成员函数引起的,下面介绍这主题。

除去所有赋值操作,结果显示正常。

隐式成员函数

StringBad 类中的问题是由自动定义的隐式成员函数引起的,这种函数的行为与类设计不符。

具体来说C++自动提供了下面这些成员函数:

  • 默认构造函数,如果没有定义构造函数
  • 复制构造函数,如果没有定义
  • 赋值操作符,如果没有定义
  • 默认析构函数,如果没有定义
  • 地址操作符,如果没有定义

 更准确地说,编译器将生成上述最后4个函数的定义---如果程序使用对象的方式要求这样做。例如,如果您将:个对象赋给另一个对象,编译器将提供赋值操作符的定义。

结果表明,StringBad 类中的问题是由隐式复制构造函数和隐式赋值操作符引起的。

默认构造函数

复制构造函数

复制构造函数的问题

注意:

 使用显式复制构造函数

解决类设计中这种问题的方法是进行深度复制(deepcopy)。

复制构造函数应当复制字符串并将副本的地址赋给s成员,而不仅仅是复制字符串地址。这样每个对象都有自己的字符串,而不是引用另一个对象的字符串。

调用析构函数时都将释放不同的字符串,而不会试图去释放已经被释放的字符串。

可以这样编写Sting的复制构造函数:

必须定义复制构造函数的原因在于,
一些类成员是使用new初始化的、指向数据的指针,而不是数据本身。

赋值操作符

C++允许类对象赋值,这是通过自动为类重载赋值操作符实现的。
这种操作符的原型如下:

赋值的问题 

解决赋值的问题

对于由于默认赋值操作符不合适而导致的问题,解决办法是提供赋值操作符(进行深度复制)定义其实现与复制构造函数相似,但也有一些差别

 代码首先检查自我复制,这是通过查看赋值操作符右边的地址(&s)是否与接收对象(this)的地址相同来完成的。如果相同,程序将返回*this,然后结束。

如果地址不同,函数将释放 str指向的内存,这是因为稍后将把一个新字符串的地址赋给 str。如果不首先使用 delete操作符,则上述字符串将保留在内存中。由于程序中不再包含指向该字符串的指针,因此这些内存被浪费掉。

改进后的新String类

头文件

// string1.h -- fixed and augmented string class definition
#include <iostream>
using std::istream;
using std::ostream;
#ifndef STRINGl_H_
#define STRINGI_H_
class String
{
private:char *str;int len;// pointer to string// length of stringstatic int num_strings;       // number of objectsstatic const int CINLIM = 80; // cin input limit
public:// constructors and other methodsString(const char *s);  // constructorString();               //.default constructorString(const String &); // copy constructor~String();// destructorint length() const { return len; }// overloaded operator methodsString &operator=(const String &);String &operator=(const char *);char &operator[](int i);const char &operator[](int i) const;// overloaded operator friendsfriend bool operator<(const String &st, const String &st2);friend bool operator>(const String &stl, const String &st2);friend bool operator==(const String &st, const String &st2);friend ostream &operator<<(ostream &os, const String &st);friend istream &operator>>(istream &is, String &st); // static functionstatic int HowMany();
};#endif

方法文件

string1.cpp

// stringl.cppString class methods
#include <cstring>
#include "string1.h" //includes <iostream>
using std::cin;
using std::cout;int String::num_strings = 0;
// static method
int String::HowMany()
{return num_strings;
}
// class methods
String::String(const char *s) // construct String fromC string
{len = std::strlen(s);// set size// allot storagestr = new char[len + 1];std::strcpy(str, s);num_strings++;
}String::String()
{len = 4;str = new char[1];str[0] = '\0';// default stringnum_strings++;
}String::String(const String &st)
{num_strings++;len = st.len;str = new char[len + 1];std::strcpy(str, st.str);
}String::~String()
{--num_strings;delete[] str;
}String &String::operator=(const String &st)
{if (this == &st)return *this;delete[] str;len = st.len;str = new char[len + 1];std::strcpy(str, st.str);return *this;
}
// assign aC string to a string
String &String::operator=(const char *s)
{delete[] str;len = std::strlen(s);str = new char[len + 1];std::strcpy(str, s);return *this;
}char &String::operator[](int i)
{return str[i];
}// read-only char access for const String
const char &String::operator[](int i) const
{return str[i];
}
// overloaded operator friends
bool operator<(const String &st1, const String &st2)
{return (std::strcmp(st1.str, st2.str) < 0);
}
bool operator>(const String &stl, const String &st2)
{return st2.str < stl.str;
}
bool operator==(const String &stl, const String &st2)
{return (std::strcmp(stl.str, st2.str) == 0);
}// simple String output
ostream &operator<<(ostream &os, const String &st)
{os << st.str;return os;
}// quick and dirty string input
istream &operator>>(istream &is, String &st)
{char temp[String::CINLIM];is.get(temp, String::CINLIM);if (is)st = temp;while (is && is.get() != '\n')continue;return is;
}

 程序文件

#include <iostream>
#include "string1.h"
const int ArSize = 10;
const int MaxLen = 81;
int main()
{using std::cin;using std::cout;using std::endl;String name;cout << "Hi,what's your name?\n>>";cin >> name;cout << name << ",please enter upto " << ArSize<< "short sayings <empty line to quit>:\n";String sayings[ArSize]; // array of objectschar temp[MaxLen];      // temporary string storageint i;for (i = 0; i < ArSize; i++){cout << i + 1 << ": ";cin.get(temp, MaxLen);while (cin && cin.get() != '\n')continue;if (!cin || temp[0] == '\0') // empty linebreak;                   // i not incrementedelsesayings[i] = temp; // overloaded assignment}int total = i;// total # of lines readcout << "Here are your sayings:\n";for (i = 0; i < total; i++)cout << sayings[i][0] << ":" << sayings[i] << endl;int shortest = 0;int first = 0;for (i = 1; i < total; i++){if (sayings[i].length() < sayings[shortest].length())shortest = i;if (sayings[i] < sayings[first])first = i;}cout << "shortest saying:\n"<< sayings[shortest] << endl;cout << "First alphabetically:\n"<< sayings[first] << endl;cout << "This program used " << String::HowMany()<< "String objects. Bye.\n";return 0;
}

运行结果

在构造函数中使用new时应注意的事项

有关返回对象的说明


返回指向const对象的引用

使用const引用的常见原因是旨在提高效率,但对于何时可以采用这种方式存在一些限制。

如果函数返回(通过调用对象的方法或将对象作为参数)传递给它的对象,可以通过传递引用来提高方法的效率。例如,假设要编写函数 Max(),它返回两个 Vector 对象中较大的一个返回对象将调用复制构造函数,而返回引用不会。

引用指向的对象应该在调用函数执行时存在。

第三,v1和v2都被声明为 const引用,因此返回类型必须为const,这样才匹配。

返回非const对象的引用

cout 能连续输出;

返回对象

返回指向对象的指针

加入指针的程序

#include <iostream>
#include "string1.h"
#include <ctime>
const int ArSize = 10;
const int MaxLen = 81;
int main()
{using namespace std;String name;cout << "Hi,what's your name?\n>>";cin >> name;cout << name << ",please enter upto " << ArSize<< "short sayings <empty line to quit>:\n";String sayings[ArSize]; // array of objectschar temp[MaxLen];      // temporary string storageint i;for (i = 0; i < ArSize; i++){cout << i + 1 << ": ";cin.get(temp, MaxLen);while (cin && cin.get() != '\n')continue;if (!cin || temp[0] == '\0') // empty linebreak;                   // i not incrementedelsesayings[i] = temp; // overloaded assignment}int total = i;// total # of lines readif (total > 0){cout << "Here are your sayings:\n";for (i = 0; i < total; i++)cout << sayings[i] << endl;String *shortest = &sayings[0];String *first = &sayings[0];for (i = 1; i < total; i++){if (sayings[i].length() < shortest->length())shortest = &sayings[i];if (sayings[i] < *first)first = &sayings[i];}cout << "shortest saying:\n"<< *shortest << endl;cout << "First alphabetically:\n"<< *first << endl;srand(time(0));int choice = rand() % total;String *favorite = new String(sayings[choice]);cout << "My favorite saying: \n " << *favorite << endl;delete favorite;}elsecout << "No much to say, eh?\n";cout << "Bye.\n";return 0;
}

析构函数的调用

  • 如果对象是动态变量,则当执行完定义该对象的程序块时,将调用该对象的析构函数。
  • 如果对象是静态变量(外部、静态、静态外部或来自名称空间),则在程序结束时将调用对象的析构函数。
  • 如果对象是用new 创建的,则仅当您显式使用 delete 删除对象时,其析构函数才会被调用。

 指针和对象小结

再谈布局new操作符

#include <iostream>
#include <string>
#include <new>
using namespace std;
const int BUF = 512;
class JustTesting
{
private:string words;int number;public:JustTesting(const string &s = "Just Testing", int n = 0){words = s;number = n;cout << words << "constructed\n";}~JustTesting() { cout << words << " destroyed\n"; }void Show() const{cout << words << ", " << number << endl;}
};int main()
{char *buffer = new char[BUF];// get a block of memoryJustTesting *pc1, *pc2;// place object in bufferpc1 = new (buffer) JustTesting;pc2 = new JustTesting("Heap1", 20); // place object on heapcout << "Memory block addresses:\n"<< "buffer: " << (void *)buffer << "    heap : " << pc2 << endl;cout << " Memory contents :\n ";cout << pc1 << " : ";pc1->Show();cout << pc2 << " : ";pc2->Show();JustTesting *pc3, *pc4;pc3 = new (buffer) JustTesting("Bad Idea", 6);pc4 = new JustTesting("Heap2", 10);cout << "Memory contents:\n";cout << pc3 << ": ";pc3->Show();cout << pc4 << ": ";pc4->Show();delete pc2;delete pc4;delete[] buffer;cout << "Done\n";return 0;
}

在使用布局new操作符时存在两个问题。首先,在创建第二个对象时,布局new操作符使用一-个新对象来覆盖用于第一个对象的内存单元。显然,如果类动态地为其成员分配内存,这将引发问题。
其次,将 delete用于 pc2 和 pc4 时,将自动调用为 pc2 和 pc4 指向的对象调用析构函数;然而,将 delete[]用于 bufer 时,不会为使用布局 new 操作符创建的对象调用析构函数。

解决方法


 

原因在于 delete 可与常规 new 操作符配合使用,但不能与布局new操作符配合使用。

例如,指针 pc3没有收到 new 操作符返回的地址,因此 delete pc3 将导致运行阶段错误。在另一方面,指针 pc1指向的地址与 buffer 相同,但 buffer 是使用new[]初始化的,因此必须使用 delete[]而不是 delete 来释放。

即使 buffer是使用 new而不是new[]初始化的,delete pc1也将释放buffer,而不是 pc1。这是因为 new/delete 系统知道已分配的 512 字节块 buffer,但对布局new 操作符对该内存块做了何种处理一无所知。

#include <iostream>
#include <string>
#include <new>
using namespace std;
const int BUF = 512;
class JustTesting
{
private:string words;int number;public:JustTesting(const string &s = "Just Testing", int n = 0){words = s;number = n;cout << words << "constructed\n";}~JustTesting() { cout << words << " destroyed\n"; }void Show() const{cout << words << ", " << number << endl;}
};int main()
{char *buffer = new char[BUF];// get a block of memoryJustTesting *pc1, *pc2;// place object in bufferpc1 = new (buffer) JustTesting;pc2 = new JustTesting("Heap1", 20); // place object on heapcout << "Memory block addresses:\n"<< "buffer: " << (void *)buffer << "    heap : " << pc2 << endl;cout << " Memory contents :\n ";cout << pc1 << " : ";pc1->Show();cout << pc2 << " : ";pc2->Show();JustTesting *pc3, *pc4;pc3 = new (buffer + sizeof(JustTesting)) JustTesting("Bad Idea", 6);pc4 = new JustTesting("Heap2", 10);cout << "Memory contents:\n";cout << pc3 << ": ";pc3->Show();cout << pc4 << ": ";pc4->Show();delete pc2;delete pc4;pc3->~JustTesting();pc1->~JustTesting();delete[] buffer;cout << "Done\n";return 0;
}

 

复习各种技术

重载<<操作符

重新定义<<操作符,定义下面友元操作函数:

转换函数

其构造函数使用new的类

相关文章:

c++primier第十二章类和动态内存

本章内容包括&#xff1a; 对类成员使用动态内存分配隐式和显式地复制构造函数隐式和显式地重载赋值操作符在构造函数中使用new所必须完成的工作使用静态类成员 将布局new操作符用于对象使用指向对象的指针实现队列抽象数据类型(ADT) 动态内存和类 复习范例和静态类成员 首…...

Ansible学习之ansible-pull命令

想要知道ansible-pull是用来做什么的&#xff0c;就需要了解Ansible的工作模&#xff0c;Ansible的工作模式有两种&#xff1a; push模式 push推送&#xff0c;这是Ansible的默认模式&#xff0c;在主控机上编排好playbook文件&#xff0c;push到远程主机上来执行。pull模式 p…...

Linux:磁盘管理

一、静态分区管理 静态的分区方法不可以动态的增加或减少分区的容量。 1、磁盘分区-fdisk 该命令是用于查看磁盘分区情况&#xff0c;和分区管理的命令 命令格式&#xff1a;fdisk [选项] 设备文件名常用命令&#xff1a; -h&#xff1a;查看分区信息 fdisk系统常用命令&…...

FP7209: 用于紫外线消毒灯的 升压LED恒流驱动芯片

现在社会对于居家消毒也越发重视起来。而居家消毒除了75%浓度酒精及各类消毒液外&#xff0c;利用紫外线灯给衣物表面、房间消毒也是一种很好的选择。FP7209 定位于低压线性恒流驱动&#xff0c;精度高、外围电路简单、使用方便且可靠性高&#xff0c;更可广泛应用于商业照明系…...

【华为HCIP实战课程二】OSPF基础介绍和OSPF RID NBMA配置详解

一、OSPF多区域 自治系统(Autonomous System) 一个自治系统是指使用同一种路由协议交换路由信息的一组路由器 1、Area0为骨干区域 2、ABR--关乎3类LSA后续详解 ABR用来连接骨干区域Area0和非骨干区域,它与骨干区域之间既可以是物理连接,也可以是逻辑上的连接。 3、AS…...

网络编程(13)——单例模式

十三、day13 今天学习如何单例模式实现逻辑层的设计。内容包括服务器如何能捕获信号使其安全退出、单例模标类 1. 什么是单例模式&#xff1f; 单例模式&#xff08;Singleton&#xff09;&#xff0c;保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点&…...

基于定制开发与2+1链动模式的商城小程序搭建策略

摘要&#xff1a;本文探讨商城小程序的搭建策略&#xff0c;对比自主组建团队和第三方开发两种方式&#xff0c;强调以第三方开发模式为主的优势。阐述在第三方开发模式下&#xff0c;结合定制开发和21链动模式&#xff0c;如何搭建一款有助于企业商业模式创新与智能商业升级的…...

银河麒麟,apt 安装软件报错640Unknown Status

今天把银行麒麟的机器恢复出厂了&#xff0c;然后apt install 安装极其不稳定&#xff0c;故障现象如下图所示&#xff1a; 错误提示里面有&#xff1a; 640 Unknown Status [IP: 106.116.184.122 80] E: 无法下载 http://archive.kylinos.cn/kylin/KYLIN-ALL/pool/universe/f…...

python UNIT 3 选择与循环(2)

目录 1。循环的优化 经典优化分析&#xff1a; 未优化的代码&#xff1a; 细节分析&#xff1a; 优化后的代码&#xff1a; 优化的细节&#xff1a; 性能对比 优化的关键在于&#xff1a; 经典习题讲解&#xff1a;(紫色的解析请重点关注一下) 1。例三 个人代码解析…...

828华为云征文|部署在线文档应用程序 CodeX Docs

828华为云征文&#xff5c;部署在线文档应用程序 CodeX Docs 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 CodeX Docs3.1 CodeX Docs 介绍3.2 CodeX Docs 部署3.3 CodeX…...

Linux的多线程(线程的创建,退出,取消请求,取消处理例程,线程属性的设置)

进程:是系统分配资源的最小单位,系统会为每一个进程分配一块独立的虚拟内存空间 线程:是系统调度的最小单位,系统不会为线程分配新的内存空间,但是线程也参与系统调度 cpu把时间片分给每一个进程&#xff0c;进程中的时间片再切分分给每一个线程&#xff0c;所以线程也会得到…...

git 本地代码关联远程仓库并推送

初始化代码仓库 如果你的本地项目还没有使用Git管理&#xff0c;首先需要在项目根目录下初始化一个Git仓库 git init添加远程仓库地址 使用 git remote add 命令添加远程仓库 git remote add origin https://github.com/username/repository.git获取远程分支信息 使用 git…...

推荐一个可以把PDF样本册转换为翻页电子书的网站

​随着互联网的普及&#xff0c;越来越多的企业和个人开始意识到线上展览的重要性。如何将实体样本册转化为线上版本&#xff0c;让更多人了解和欣赏自己的产品与服务&#xff1f; 一、网站简介 这款PDF样本册免费上传网站名为“FLBOOK”&#xff0c;致力于为广大用户提供便捷…...

【Linux 23】线程池

文章目录 &#x1f308; 一、线程池的概念&#x1f308; 二、线程池的应用场景&#x1f308; 三、线程池的实现 &#x1f308; 一、线程池的概念 线程池 (thread pool) 是一种利用池化技术的线程使用模式。 虽然创建线程的代价比创建进程的要小很多&#xff0c;但小并不意味着…...

Rust SQLite 跨平台使用

引言 Rust因其内存安全性和高性能受到越来越多开发者的青睐。在许多项目中&#xff0c;SQLite作为一种轻量级的嵌入式数据库&#xff0c;与Rust的结合为跨平台应用程序提供了强大的支持。本文将详细探讨Rust如何实现跨平台功能&#xff0c;如何在不同平台上使用Rust库&#xf…...

docker运行arm64架构的镜像、不同平台镜像构建

背景 Docker 允许开发者将应用及其依赖打包成一个轻量级、可移植的容器&#xff0c;实现“一次构建&#xff0c;到处运行”的目标。然而&#xff0c;不同的操作系统和硬件架构对容器镜像有不同的要求。例如&#xff0c;Linux 和 Windows 系统有不同的文件系统和系统调用&#…...

vue基于Spring Boot框架的高校实验室预约管理系统

目录 毕设制作流程功能和技术介绍系统实现截图开发核心技术介绍&#xff1a;使用说明开发步骤编译运行代码执行流程核心代码部分展示可行性分析软件测试详细视频演示源码获取 毕设制作流程 &#xff08;1&#xff09;与指导老师确定系统主要功能&#xff1b; &#xff08;2&am…...

Linux中find命令详解

记录linux中find命令的详细用法。 文章目录 find命令简介基本语法常用选项-name-iname-type-size-mtime,-atime,-ctime-perm-user-group-delete-exec-printand or find --help find命令简介 find 是一个搜索目录树以查找一个文件或一组文件的程序。它遍历目录树并报告与用户规…...

无水印短视频素材下载网站有哪些?十个高清无水印视频素材网站分享

你知道怎么下载无水印视频素材吗&#xff1f;今天小编就给大家推荐十个高清无水印视频素材下载的网站&#xff0c;如果你也是苦于下载高清无水印的短视频素材&#xff0c;赶紧来看看吧&#xff5e; 1. 稻虎网 首推的是稻虎网。这个网站简直就是短视频创作者的宝库。无论你需要…...

SpringBoot+Activiti7工作流入门实例

目录 文章目录 目录准备Activiti建模工具1、BPMN-js在线设计器1.1 安装1.2 使用说明1.3运行截图2、IDEA安装Activiti Designer插件2.1安装插件2.2 设置编码格式防止中文乱码2.3 截图简单工作流入门实例1. 新建Spring Boot工程2. 引入Activiti相关依赖添加版本属性指定仓库添加依…...

Azure OpenAI检索增强微调:使用 GPT-4o 对 GPT-4o mini 进行微调,以适应特定领域的应用

定制是关键&#xff01; 生成式人工智能对企业最有影响力的应用之一是创建自然语言界面&#xff0c;这些界面经过定制&#xff0c;可以使用特定领域和用例数据来提供更好、更准确的响应。这意味着回答有关特定领域的问题&#xff0c;例如银行、法律和医疗领域。 我们经常谈…...

ISP Pipeline

系列文章目录 文章目录 系列文章目录前言一、RAW域二、RGB域三、YUV域总结 前言 一、RAW域 黑电平校正&#xff08;BLC&#xff09;数字增益调整&#xff08;DGain&#xff09;自动白平衡&#xff08;AWB&#xff09;局部色调映射&#xff08;LTM&#xff09;坏点修复&#xf…...

< IDE编程环境配置>

IDE编程环境配置 LIB&#xff0c;DLL区别 我们在写项目时会链接&#xff08;调用&#xff09;第3方库&#xff0c;或者比如在vs的解决方案solution创建项目project时&#xff0c;不仅可以开发可执行程序exe&#xff08;可单独运行&#xff09;&#xff08;windows/控制台 应用…...

Golang | Leetcode Golang题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; func findDisappearedNumbers(nums []int) (ans []int) {n : len(nums)for _, v : range nums {v (v - 1) % nnums[v] n}for i, v : range nums {if v < n {ans append(ans, i1)}}return }...

【Spring Boot 入门三】Spring Boot与数据库集成 - 构建数据驱动的应用

一、引言 在之前的文章中&#xff0c;我们已经对Spring Boot有了初步的认识&#xff0c;了解了如何构建第一个Spring Boot应用&#xff0c;以及如何通过配置文件来掌控应用的设置。这些知识为我们进一步探索Spring Boot与数据库的集成奠定了坚实的基础。 数据库是现代应用的核…...

Web 服务器与动态脚本语言通信的接口协议有哪些

Web 服务器与动态脚本语言通信的接口协议主要有以下几种&#xff1a; 一、FastCGI&#xff08;Fast Common Gateway Interface&#xff09; 特点&#xff1a;使用持久进程处理请求&#xff0c;减少了进程启动和关闭的开销&#xff0c;提高了性能和可扩展性。多个请求可由同一个…...

ESXI识别服务器磁盘,虚拟机显示无效

ESXI识别服务器磁盘&#xff0c;虚拟机显示无效 系统意外断电识别不到磁盘的情况下可以管理-》硬件-》搜索磁盘名称&#xff0c;选择切换直通&#xff0c;则虚拟机正常。...

【C++】 vector 迭代器失效问题

【C】 vector 迭代器失效问题 一. 迭代器失效问题分析二. 对于vector可能会导致其迭代器失效的操作有&#xff1a;1. 会引起其底层空间改变的操作&#xff0c;都有可能是迭代器失效2. 指定位置元素的删除操作--erase3. Linux下&#xff0c;g编译器对迭代器失效的检测并不是非常…...

【Spring基础3】- Spring的入门程序

目录 3-1 Spring的下载3-2 Spring的 jar 包3-3 第一个 Spring程序第一步&#xff1a;添加spring context的依赖&#xff0c;pom.xml配置如下第二步&#xff1a;添加junit依赖第三步&#xff1a;定义bean&#xff1a;User第四步&#xff1a;编写spring的配置文件&#xff1a;bea…...

golang学习笔记22-面向对象(四):接口【重要】

本节也是GO核心部分&#xff0c;很重要。 注&#xff1a;由于导包语句已经在19讲&#xff08;笔记19&#xff1a;面向对象的引入&#xff09;展示过了&#xff0c;所以这里就不展示了。 一、定义与实现 (1)接口中可以定义一组方法&#xff0c;但不需要实现&#xff0c;不需要…...

公司建设网站的申请报告/厨师培训

Boss的需要时这样的&#xff0c;Item是可变大小的&#xff0c;同时根据不同的Window size&#xff0c;来确定Item的结构和大小Window 小的时候是 大的时候是这样的&#xff1a; 当然这size变化的过程中也允许其他结构&#xff0c;我这里只是举了最大和最小时候的样子。 当拿到需…...

网站seo应用/百度网站认证

题目描述 八尾勇喜欢吃苹果。她今天吃掉了 x(0\le x \le 100)x(0≤x≤100) 个苹果。英语课上学到了 apple 这个词语&#xff0c;想用它来造句。如果她吃了 1 个苹果&#xff0c;就输出 Today, I ate 1 apple.&#xff1b;如果她没有吃&#xff0c;那么就把 1 换成 0&#xff1…...

wordpress docs/外链代发平台

一、问题概述 生产者消费者模式是一个十分经典的多线程之间协作的模式&#xff0c;实际上主要包含了两类两类线程&#xff1a;   一类是生产者线程&#xff0c;用于生产数据&#xff1b;   一类是消费者线程&#xff0c;用于消费数据。  为了解耦生产者与消费者的关系&…...

网站建设方法叁金手指下拉丶/下载百度到桌面上

最近在反编译class和jar包的时候&#xff0c;发现部分class无法反编译出来&#xff0c;换了最新版本的jd-gui和多个版本都不行&#xff0c;只能放弃了 解决方案&#xff1a;GitHub上找Luyten这个工具反编译 luyten是Procyon的GUI&#xff0c;是一款操作简单、功能实用的java反编…...

莱州教研室网站/百度云盘资源

git mercurialJDK团队希望通过Project Skara来研究JDK源代码管理的替代方案&#xff0c;该替代方案自2008年以来一直在使用Mercurial存储库。 “退休” Mercurial并选择Git是个好主意吗&#xff1f; 投票表决&#xff0c;看看Java冠军Stephen Colebourne对这次讨论要说些什么。…...

wordpress 嵌入播放ppt/上海网站seo

开发软件&#xff0c;包括linux版 jdk&#xff0c;mysql&#xff0c;nginx&#xff0c;tomcat&#xff0c;redis&#xff0c;软件日志文件&#xff08;测试使用&#xff09; 有可能底下需要使用&#xff0c;如果需要请自行下载 链接&#xff1a;https://pan.baidu.com/s/1xhdD…...