C++:列表初始化 + 右值引用与移动语义(附完整代码)

一. C++11的发展历史

C++11是C++的第二个主要版本,并且是从C++98起的最重要更新。它引入了大量更改,标准化了既有实践,并改进了对C++程序员可用的抽象。在它最终由ISO在2011年8月12日采纳前,人们曾使用名称“C++0X”,因为它曾被期待在2010年之前发布。C++03与C++11期间花了8年时间,故而是迄今为止最长的版本间隔。从那时起,C++有规律地每3年更新一次。

二. 列表初始化:万物皆可 {} 的统一初始化方案

C++98 中初始化方式杂乱(数组用 {}、类用构造函数、内置类型直接赋值),C++11引入列表初始化(统一初始化),通过{}实现 “一切对象皆可初始化”,兼顾简洁性与安全性。

2.1 核心用法:支持所有对象类型

C++11中的{}:

  • 内置类型支持,自定义类型也支持,自定义类型本质是类型转换,中间会产生临时对象,最后优化变成直接构造
  • {}初始化的过程中,可以省略掉=
  • C++11列表初始化的本意是实现一个大统一的初始化方法,其次他在有些场景下带来的不少便利,如容器push多参数构造的对象时,{}初始化会很方便。
struct Point { int _x; int _y; }; class Date { public: Date(int year = 1, int month = 1, int day = 1) :_year(year) , _month(month) , _day(day) { cout << "Date(int year, int month, int day)" << endl; } Date(const Date& d) :_year(d._year) , _month(d._month) , _day(d._day) { cout << "Date(const Date& d)" << endl; } private: int _year; int _month; int _day; }; void Insert(const Date& d) { } Date func() { //Date d(2025, 11, 15); //return d; //return { 2025,11,15 }; //Date d; //return d; return {}; } int main() { // C++98 int array1[] = { 1,2,3,4,5 }; int array2[5] = { 0 }; Point p = { 1,2 }; // C++11 // ⼀切皆可用列表初始化,且可以不加= int x1 = { 2 }; // 自定义类型支持 // 这里本质是用{2025, 1, 1}构造一个Date临时对象 // 临时对象再去拷⻉构造d1,编译器优化后合二为一变成{2025, 1, 1}直接构造初始化d1 // 运行一下,我们可以验证上面的理论,发现是没调用拷⻉构造的 Date d1 = { 2025, 1, 1 }; // 这里d2引用的是{ 2024, 7, 25 }构造的临时对象 const Date& d2 = { 2024, 7, 25 }; // 需要注意的是C++98支持单参数时类型转换,也可以不用{} Date d3 = { 2025 }; Date d4 = 2025; // 可以省略掉= Point p1{ 1, 2 }; int x2{ 2 }; Date d6{ 2024, 7, 25 }; const Date& d7{ 2024, 7, 25 }; // 不支持,只有{}初始化,才能省略= // Date d8 2025; vector<Date> v; v.push_back(d1); v.push_back(Date(2025, 1, 1)); // 比起有名对象和匿名对象传参,这里{}更有性价比 v.push_back({ 2025, 1, 1 }); Insert({ 2025,11,15 }); return 0; }

2.2 C++11中的std::initializer_list

std::initializer_list是 C++11 新增的轻量级容器,本质存储两个指针(指向数组首尾),数组存储初始化列表中的数据(位于栈上)。其核心接口包括begin()end()size(),支持迭代器遍历。

  • 上面的初始化已经很方便,但是对象是容器初始化还是不太方便,比如一个vector对象,我想用N个值去构造初始化,那么我们得实现多个构造函数才能支持,vector<int> v1= {1,2,3}; vector<int> v2 = {1,2,3,4,5};
  • C++库中提出std::initializer_list这个类,auto il = { 10, 20, 30 }; // the type of il is an initializer_list ,这个类的本质是底层开⼀个数组,将数据拷⻉过来,std::initializer_list内部有两个指针分别指向数组的开始和结束。
  • std::initializer_list支持迭代器遍历
  • 容器支持一个std::initializer_list的构造函数,也就支持任意多个值构成的{x1,x2,x3……}进行初始化。STL中的容器支持任意多个值构成的{x1,x2,x3……}进行初始化,就是通过std::initializer_list的构造函数支持的。
int main() { vector<int> v1 = { 1,2,3,4 }; vector<int> v2 = { 1,2,3,4,5,6,7,7 }; // 里面的括号是pair列表初始化,外面的是initialize_list map<string, string> dict = { {"sort","排序"},{"string","字符串"} }; v1 = { 10,20,30 }; auto il = { 10,20,30 }; cout << typeid(il).name() << endl; std::initializer_list<int> mylist; mylist = { 10,20,30 }; cout << sizeof(mylist) << endl; // 这里begin和end返回的值initializer_list对象中存的两个指针 // 这两个指针的值跟i的地址跟接近,说明数组存在栈上 int i = 0; cout << mylist.begin() << endl; cout << mylist.end() << endl; cout << &i << endl; return 0; }

三. 右值引用与移动语义:彻底解决拷贝效率问题

C++98 中左值引用(Type&)无法绑定右值,大量临时对象的拷贝导致性能浪费。C++11 新增右值引用(Type&&移动语义,通过 “窃取” 右值对象的资源,替代拷贝操作,大幅提升效率。

3.1 基础概念:左值与右值

  • 左值:是⼀个表示数据的表达式(如变量名或解引⽤的指针),⼀般是有持久状态,存储在内存中,我们可以获取它的地址,左值可以出现赋值符号的左边,也可以出现在赋值符号右边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。
  • 右值:右值也是⼀个表⽰数据的表达式,要么是字⾯值常量、要么是表达式求值过程中创建的临时对象等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。
  • 核心区别:能否取地址是左值和右值的核心区别。
int main() { // 左值:可以取地址 // 以下的p,b,c,*p,s,s[0]就是常见的左值 int* p = new int(0); int b = 1; const int c = b; *p = 10; string s("11111111111111"); s[0] = 'x'; cout << &p << endl; cout << &b << endl; cout << &c << endl; cout << &(*p) << endl; cout << &s << endl; cout << (void*)&s[0] << endl; // 右值:不能取地址 double x = 1.1, y = 2.2; // 以下几个10、x + y、fmin(x, y)、string("11111")都是常见的右值 10; x + y; fmin(x, y); string("11111"); // 编译报错 //cout << &10 << endl; //cout << &(x+y) << endl; //cout << &(fmin(x, y)) << endl; //cout << &string("11111") << endl; }

3.2 右值引用语法

  • 右值引用专门绑定右值,延长其生命周期;
  • 左值引用(非 const)不能绑定右值,但const左值引用可绑定右值(但无法修改);
  • 右值引用不能直接绑定左值,但可通过std::move()强制转换左值为右值(move本质是类型转换,不移动数据)。

int main() { int* p = new int(0); int b = 1; const int c = b; *p = 10; string s("11111111111111"); s[0] = 'x'; double x = 1.1, y = 2.2; // 左值引用给左值取别名 int& r1 = b; int*& r2 = p; int& r3 = *p; string& r4 = s; char& r5 = s[0]; // 右值引用给右值取别名 int&& rr1 = 10; double&& rr2 = x + y; double&& rr3 = fmin(x, y); string&& rr4 = string("11111"); // 左值引用不能直接引用右值,但是const左值引用可以引用右值 const int& rx1 = 10; const double& rx2 = x + y; const double& rx3 = fmin(x, y); const string& rx4 = string("11111"); // 右值引用不能直接引用左值,但是右值引用可以引用move(左值) int&& rrx1 = move(b); int*&& rrx2 = move(p); int&& rrx3 = move(*p); string&& rrx4 = move(s); string&& rrx5 = (string&&)s; // b、r1、rr1都是变量表达式,都是左值 cout << &b << endl; cout << &r1 << endl; cout << &rr1 << endl; // 这里要注意的是,右值引用后rr1的属性是左值,所以不能再被右值引用绑定,除非move一下 // 后面还会再讲到的 int& r6 = r1; // int&& rrx6 = rr1; int&& rrx6 = move(rr1); return 0; }

3.3 引用延长生命周期

我们知道引用可以延长对象生命周期,那么临时对象和匿名对象的生命周期可以通过右值引用来延长,const的左值引用也行,但是不能修改。

class A { public: A() { cout << "A()" << endl; } ~A() { cout << "~A()" << endl; } }; int main() { A aa1; // 延长匿名对象的生命周期 const A& ref1 = A();// const左值引用,但是这样就不能修改了 A&& ref2 = A();// 右值引用 cout << "main end()" << endl; return 0; }

3.4 右值和左值的参数匹配

  • C++98中,我们实现一个const左值引用作为参数的函数,那么实参传递左值和右值都可以匹配
  • C++11之后,分别重载左值引用,const左值引用,右值引用作为形参的f函数,那么实参是左值会匹配f(左值引用),实参是const左值会匹配(const左值引用),实参是右值会匹配f(右值引用)。
  • 右值引用变量在用于表示式时属性是左值,这个我们后面还会讲到的,到时候大家就会对它有更直观的认知了。
void f(int& x) { std::cout << "左值引用重载 f(" << x << ")\n"; } void f(const int& x) { std::cout << "到 const 的左值引用重载 f(" << x << ")\n"; } void f(int&& x) { std::cout << "右值引用重载 f(" << x << ")\n"; } int main() { int i = 1; const int ci = 2; f(i); // 调用 f(int&) f(ci); // 调用 f(const int&) f(3); // 调用 f(int&&),如果没有 f(int&&) 重载则会调用 f(const int&) f(std::move(i)); // 调用 f(int&&) // 右值引用变量在用于表达式时是左值 int&& x = 1; f(x); // 调用 f(int& x) f(std::move(x)); // 调用 f(int&& x) return 0; }

3.5 移动语义核心:移动构造与移动赋值

先回顾一下左值引用的一些场景

左值引⽤主要使⽤场景是在函数中左值引⽤传参和左值引⽤传返回值时减少拷⻉,同时还可以修改实参和修改返回对象的价值。左值引⽤已经解决⼤多数场景的拷⻉效率问题,但是有些场景不能使⽤传左值引⽤返回,如addStrings,generate函数,C++98中的解决⽅案只能是被迫使⽤输出型参数解决。那么C++11以后这⾥可以使⽤右值引⽤做返回值解决吗?显然是不可能的,因为这⾥的本质是返回对象是⼀个局部对象,函数结束这个对象就析构销毁了,右值引⽤返回也⽆法改变对象已经析构销毁的事实。

移动构造和移动赋值

  • 移动构造函数是一种构造函数,类似拷贝构造函数,移动构造函数要求第一个参数是该类类型的引用,但是不同的是要求这个参数是右值引用,如果还有其他参数,额外的参数必须有缺省值。
  • 移动赋值是一个赋值运算符重载,他跟拷贝赋值构成函数重载,类似拷贝赋值函数,移动赋值函数要求第一个参数是该类类型的引用,但是不同的是要求这个参数是右值引用。
  • 对于像string/vector这样的深拷贝的类或者深拷贝的成员变量的类,移动构造和移动赋值才有意义,因为移动构造和移动赋值的第一个参数都是右值引用的类型,他的本质是要“窃取”引用的右值对象的资源,而不是像拷贝构造函数和拷贝赋值那样去拷贝资源,提高效率。下面的Lotso::string样例实现了移动构造和移动赋值,我们需要结合场景去理解。
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<assert.h> #include<string.h> #include<algorithm> using namespace std; namespace Scy { class string { public: typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _str; } iterator end() { return _str + _size; } const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } string(const char* str = "") :_size(strlen(str)) , _capacity(_size) { cout << "string(char* str)-构造" << endl; _str = new char[_capacity + 1]; strcpy(_str, str); } void swap(string& s) { ::swap(_str, s._str); ::swap(_size, s._size); ::swap(_capacity, s._capacity); } // 拷贝构造 string(const string& s) { cout << "string(const string& s) -- 拷贝构造" << endl; reserve(s._capacity); for (auto ch : s) { push_back(ch); } } // 移动构造 string(string&& s) { cout << "string(string&& s) -- 移动构造" << endl; swap(s); } string& operator=(const string& s) { cout << "string& operator=(const string& s) -- 拷贝赋值" << endl; if (this != &s) { _str[0] = '\0'; _size = 0; reserve(s._capacity); for (auto ch : s) { push_back(ch); } } return *this; } // 移动赋值 string& operator=(string&& s) { cout << "string& operator=(string&& s) -- 移动赋值" << endl; swap(s); return *this; } ~string() { //cout << "~string() -- 析构" << endl; delete[] _str; _str = nullptr; } char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } void reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; if (_str) { strcpy(tmp, _str); delete[] _str; } _str = tmp; _capacity = n; } } void push_back(char ch) { if (_size >= _capacity) { size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; ++_size; _str[_size] = '\0'; } string& operator+=(char ch) { push_back(ch); return *this; } const char* c_str() const { return _str; } size_t size() const { return _size; } private: char* _str = nullptr; size_t _size = 0; size_t _capacity = 0; }; // 传值返回需要拷贝 string addStrings(string num1, string num2) { string str; int end1 = num1.size() - 1, end2 = num2.size() - 1; // 进位 int next = 0; while (end1 >= 0 || end2 >= 0) { int val1 = end1 >= 0 ? num1[end1--] - '0' : 0; int val2 = end2 >= 0 ? num2[end2--] - '0' : 0; int ret = val1 + val2 + next; next = ret / 10; ret = ret % 10; str += ('0' + ret); } if (next == 1) str += '1'; reverse(str.begin(), str.end()); cout << &str << endl; return str; } } int main { bit::string s1("xxxxx"); // 拷⻉构造 bit::string s2 = s1; // 构造+移动构造,优化后直接构造 bit::string s3 = bit::string("yyyyy"); // 移动构造 bit::string s4 = move(s1); cout << "******************************" << endl; return 0; }

再补充两个场景

// 场景一 int main() { Scy::string ret = Scy::addStrings("11111", "2222"); cout << ret.c_str() << endl; cout << &ret << endl; } // 场景二: int main() { Scy::string ret; // …… ret = Scy::addStrings("11111", "2222"); cout << ret.c_str() << endl; cout << &ret << endl; }
3.5.1 右值对象构造,只有拷贝构造,没有移动构造的场景
  • 下图1中展现了 vs2019 debug 环境下编译器对拷贝的优化,左边为不优化的情况下,两次拷贝构造,右边为编译器优化的场景下连续步骤中的拷贝合二为一变为一次拷贝构造。
  • 需要注意的是在 vs2019的release和 vs2022的debug和release,下面代码优化十分恐怖,会直接将strd对象的构造,str拷贝构造临时对象,临时对象拷贝构造ret对象,合三为一,变为直接构造,要理解这个优化要结合局部对象⽣命周期和栈帧的⻆度理解,如图三。
  • linux下可以将下⾯代码拷⻉到test.cpp⽂件,编译时⽤g++ test.cpp -fno-elide-constructors的⽅式关闭构造优化,运⾏结果可以看到图1左边没有优化的两次拷⻉。

图一

3.5.2 右值对象构造,有拷⻉构造,也有移动构造的场景
  • 图2展示了vs2019 debug环境下编译器对拷⻉的优化,左边为不优化的情况下,两次移动构造,右边为编译器优化的场景下连续步骤中的拷⻉合⼆为⼀变为⼀次移动构造。
  • 需要注意的是在vs2019的release和vs2022的debug和release,下⾯代码优化为⾮常恐怖,会直接将str对象的构造,str拷⻉构造临时对象,临时对象拷⻉构造ret对象,合三为⼀,变为直接构造。要理解这个优化要结合局部对象⽣命周期和栈帧的⻆度理解,如图3所示。
  • linux下可以将下⾯代码拷⻉到test.cpp⽂件,编译时⽤g++ test.cpp -fno-elide-constructors的⽅式关闭构造优化,运⾏结果可以看到图1左边没有优化的两次移动。

图二

图三

3.5.3 右值对象赋值,只有拷⻉构造和拷⻉赋值,没有移动构造和移动赋值的场景
  • 图4左边展示了vs2019 debug和g++ test.cpp -fno-elide-constructors关闭优化环境
    下编译器的处理,⼀次拷⻉构造,⼀次拷⻉赋值。
  • 需要注意的是在vs2019的release和vs2022的debug和release,下⾯代码会进⼀步优化,直接构造要返回的临时对象,str本质是临时对象的引⽤,底层⻆度⽤指针实现。运⾏结果的⻆度,我们可以看到str的析构是在赋值以后,说明str就是临时对象的别名。

图四

3.5.4 右值对象赋值,既有拷⻉构造和拷⻉赋值,也有移动构造和移动赋值的场景
  • 图5左边展示了vs2019 debug和g++ test.cpp -fno-elide-constructors关闭优化环境
    下编译器的处理,⼀次移动构造,⼀次移动赋值。
  • 需要注意的是在vs2019的release和vs2022的debug和release,下⾯代码会进⼀步优化,直接构造要返回的临时对象,str本质是临时对象的引⽤,底层⻆度⽤指针实现。运⾏结果的⻆度,我们可以看到str的析构是在赋值以后,说明str就是临时对象的别名。

图五

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

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

相关文章

北京top10研究生留学机构全面解析:录取率高,申请成功保障

北京top10研究生留学机构全面解析:录取率高,申请成功保障一。、北京研究生如何选择高录取率的留学中介?我是从业八年的国际教育规划师张明,接触过大量在京求学的研究生申请者。许多同学在咨询时都表达过相似的困惑…

2026年浙江危废焚烧炉优质供应商排行榜,道捷环境实力如何?

本榜单依托危废处置行业全维度市场调研与真实客户口碑反馈,深度筛选出五家危废焚烧炉标杆供应商,重点考量技术创新性、合规稳定性、成本控制能力及服务全周期覆盖度,为产废企业(化工、制药、半导体等)精准匹配适配…

时序数据库选型与实战:IoTDB 在工业物联网场景下的上手与踩坑总结

文章目录 为什么需要认真做一次时序数据库选型&#xff1f;时序数据库选型时重点关注哪些问题&#xff1f;写入能力与稳定性存储效率与长期成本查询能力与使用体验 IoTDB 的场景定位&#xff1a;以工业时序数据为核心能源电力航空航天交通运输钢铁冶炼通用物联网 上手流程&…

OpenCV实战:透视变换原理与发票矫正全解析

在计算机视觉领域&#xff0c;透视变换是矫正“透视畸变”的核心技术&#xff0c;可将倾斜拍摄的发票、文档、名片等转化为正面平视效果&#xff0c;彻底消除“近大远小”的视觉偏差。本文从原理到实战&#xff0c;拆解透视变换的实现逻辑&#xff0c;结合可直接运行的发票矫正…

福州硕士留学机构top10推荐,无隐形消费承诺,安心留学首选

福州硕士留学机构top10推荐,无隐形消费承诺,安心留学首选从业八年的国际教育规划师,我在工作中遇到许多寻求硕士留学服务的家庭,他们最常提出的问题便是:“在福州,如何选择一家可靠且无隐性消费的留学中介?” 这…

如何查阅最新的研究论文:实用方法与技巧指南

刚开始做科研的时候&#xff0c;我一直以为&#xff1a; 文献检索就是在知网、Google Scholar 里反复换关键词。 直到后来才意识到&#xff0c;真正消耗精力的不是“搜不到”&#xff0c;而是—— 你根本不知道最近这个领域发生了什么。 生成式 AI 出现之后&#xff0c;学术检…

多线程与操作系统相关 手搓线程池

我不只是告诉你代码是什么&#xff0c;更会告诉你为什么这么写&#xff0c;以及在面试中如何通过这些细节展示你的功底。 我们将代码拆解为五个板块&#xff1a;核心成员变量、拒绝策略、构造方法、核心调度逻辑、工作线程与内部原理。 第一板块&#xff1a;核心成员变量&…

互联网大厂Java求职面试实战:核心技术栈与电商场景深度解析

互联网大厂Java求职面试实战&#xff1a;核心技术栈与电商场景深度解析 面试背景与故事场景 本次面试设定在一家知名互联网大厂&#xff0c;场景为电商场景下的Java开发岗位。面试官严肃专业&#xff0c;面对搞笑且略显水货的程序员谢飞机&#xff0c;展开了三轮技术与业务结…

最新彩虹云商城 前端用户后台美化版模版源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 最新彩虹云商城 前端用户后台美化版模版源码 二、效果展示 1.部分代码 代码如下&#xff08;示例&#xff09;&#xff1a; 2.效果图展示 三、学习资料下载 蓝奏云&#xff1a;ht…

计算机网络相关 讲一下rpc与传统http的区别

这是一个非常硬核且经典的问题。要真正理解 RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;和 HTTP 的区别&#xff0c;以及如何手写一个 RPC 框架&#xff0c;我们需要深入操作系统的网络层、IO 模型以及序列化协议。第一部分&#xff1a;RPC 与 …

OpenCode Skills 使用指南

本文档介绍如何在 OpenCode 中使用 Agent Skills 扩展 AI 编程助手的能力。 目录 什么是 Skills安装 Skills使用 Skills注意事项常见问题相关资源 什么是 Skills Skills 是可重用的 AI Agent 能力扩展&#xff0c;通过 SKILL.md 文件定义&#xff0c;包含 YAML frontmatter&…

如何搜索硕士论文:实用技巧与高效方法指南

刚开始做科研的时候&#xff0c;我一直以为&#xff1a; 文献检索就是在知网、Google Scholar 里反复换关键词。 直到后来才意识到&#xff0c;真正消耗精力的不是“搜不到”&#xff0c;而是—— 你根本不知道最近这个领域发生了什么。 生成式 AI 出现之后&#xff0c;学术检…

如何录制高品质音效素材?2026指南+10个免费素材站推荐

根据《2025-2030年中国音效素材行业市场全景评估及投资战略咨询报告》显示&#xff0c;随着短视频、直播、影视等领域的爆发式增长&#xff0c;高品质音效素材的需求持续上升&#xff0c;越来越多创作者选择自主录制音效以实现个性化表达。那么&#xff0c;怎样才能产出专业级的…

纯 Node.js 编译 LaTeX:无需 TeX Live、无需宏包管理的工程级方案(node-latex-compiler)

&#x1f680; 纯 Node.js 编译 LaTeX&#xff1a;无需 TeX Live、无需宏包管理的工程级方案&#xff08;node-latex-compiler&#xff09; 告别 TeX Live / MiKTeX / 宏包地狱&#xff0c;在 Node 环境下一行代码完成 LaTeX → PDF。 如果你曾尝试在 Node / Electron / CI / D…

Dapr (分布式应用运行时) 入门:不改代码实现“服务调用重试”与“分布式追踪”,Sidecar 模式的终极形态

摘要: 在微服务架构演进的十年间&#xff0c;无论是 Spring Cloud 还是 Istio&#xff0c;都在不断探索如何降低业务代码与基础设施的耦合。微软开源的 Dapr (Distributed Application Runtime) 则给出了“Sidecar 模式”的终极答案&#xff1a;将状态管理、发布订阅、服务调用…

常见影视转场音效素材下载网站有哪些?(2026年1月盘点)

根据《2025年中国数字创意产业发展报告》显示&#xff0c;2025年我国数字创意产业规模突破6万亿元&#xff0c;其中影视制作领域对音效素材的需求同比增长35%&#xff0c;尤其是影视转场音效素材&#xff0c;成为视频内容提升节奏感和观赏性的关键元素。就像做菜需要调料一样&a…

学长亲荐2026TOP10AI论文软件:本科生毕业论文写作全测评

学长亲荐2026TOP10AI论文软件&#xff1a;本科生毕业论文写作全测评 2026年AI论文写作工具测评&#xff1a;为什么你需要这份榜单&#xff1f; 随着人工智能技术的不断成熟&#xff0c;AI写作工具逐渐成为高校学生撰写毕业论文的重要辅助工具。然而&#xff0c;面对市场上琳琅…

Node.js 已死?Bun 1.2 深度评测:HTTP 吞吐量是 Node 的 3 倍,兼容性到底如何?

摘要: 2024 年&#xff0c;前端运行时领域最大的变量莫过于 Bun 1.2 的发布。作为“Node.js 杀手”&#xff0c;Bun 号称 HTTP 吞吐量是 Node 的 3 倍&#xff0c;启动速度快 4 倍。但在生产环境中&#xff0c;标榜的性能数据能否兑现&#xff1f;号称的 “Drop-in Replacement…

Excel效率神器:巧用ISFORMULA与ISREF函数实现智能统计

还在为Excel表格中混合了公式和数值的数据汇总而头疼吗&#xff1f;两个函数一个技巧&#xff0c;教你实现智能数据识别与统计&#xff01; 一、两个关键函数&#xff1a;数据类型的“火眼金睛” 1. ISFORMULA函数 - 公式检测器 ISFORMULA(单元格引用) 功能&#xff1a;判断指…

Fortra GoAnywhere MFT 关键反序列化漏洞分析工具

Fortra GoAnywhere MFT CVE-2025-10035 漏洞分析工具 项目概述 本项目是针对Fortra GoAnywhere MFT中CVE-2025-10035漏洞的分析与利用工具。该漏洞存在于License Servlet组件中&#xff0c;由于不安全的Java对象反序列化机制&#xff0c;攻击者可以通过提交带有有效签名的伪造许…