【C++】——vector深度剖析模拟实现

低头赶路,敬事如仪
目录
1、模拟vector
1.1底层结构
1.2构造析构
1.3尾插扩容
1.4迭代器
1.5增删查改
1.6模拟中的注意事项
2、vector模拟补充
2.1迭代器区间构造问题
2.2memcpy深浅拷贝问题
2.3动态二维数组的模拟及遍历
1、模拟vector
想要模拟实现自己的vector,得知其所以然!
分析一下STL源码里的vector底层成员变量

可以看到是三个迭代器类型成员变量,迭代器类型是什么呢?

经过typedef的底层指针,而T类型是模版类的参数。
大致框架如图:

1.1底层结构
根据我们刚才所查看的源码,我们要使用三个迭代器,要使用迭代器,我们可以使用指针进行模拟。
namespace xc
{//设置成模板 兼容各种参数 但是不能分离编译否则链接错误template<class T>class vector{public:typedef T* iterator;private:iterator _start = nullptr;//指向容器开始iterator _finish = nullptr;//指向有效数据下一个位置iterator _end_of_storage = nullptr;//指向空间容量的下一个位置};
}
写出三个迭代器(指针)后,我们可以接着实现构造函数:需要初始化三个迭代器,所以我们给予初始值nullptr。然后进行开辟空间。
1.2构造析构
实现常用的构造析构以及赋值重载
/* vector(){}*///C++11 强制生成默认构造vector() = default;//优先匹配构造函数,防止非法的间接寻址问题vector(size_t n, const T& val = T()){reserve(n);for (size_t i=0; i < n; i++){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i=0; i < n; i++){push_back(val);}}vector(long long n, const T&val = T()){reserve(n);for (long long i=0; i < n; i++){push_back(val);}}//类模板的成员函数还可以继续是函数模板template<class InputIterator> //写成模板是为了兼容所有容器vector(InputIterator first, InputIterator last){while(first != last){push_back(*first);++first;}}// v1(v)vector(const vector<T>& v){reserve(v.size());for (auto& e : v){push_back(e);}}void clear(){_finish = _start;}v1=v//vector<T>& operator=(const vector<T>&v)//{// if (this != &v)// {// clear();// reserve(v.size());// for (auto& e : v)// {// push_back(e);// }// }// return *this;//}void swap(vector<T>&v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}//现代写法 V1=vvector<T>& operator=(const vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[]_start;_start = _finish = _end_of_storage = nullptr;}}
1.3尾插扩容
想要实现尾插的操作,根据之前的经验,可以知道需要复用一些常用的简单接口(size() capacity() reserve() 等)
size_t size()const { return _finish - _start; }size_t capacity()const { return _end_of_storage - _start; }bool empty()const { _start == _finish; }//void reserve(size_t n)
//{
// if (n > capacity())
// {
// T* tmp = new T[n];
// memcpy(tmp, _start, sizeof(T));
// delete[]_start;// _start = tmp;
// _finish = _start + size();//这是错误的 _start 已经是扩容后的 start了 而size调用的是 finish - start
// //解决方法 可以先更新 finish 或者记录一下 size的值
// _end_of_storage = _start + n;
// }
//}void reserve(size_t n)
{if (n > capacity()){size_t old_size = size();T* tmp = new T[n];memcpy(tmp, _start, size()*sizeof(T));delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = tmp + n;}
}void reseize(size_t n, T val = T())//内置类型也具有的构造析构等函数行为 但是并没有概念
{if (n < size()){_finih = _start + n;}else{reserve(n);while (_finsh < _start+n){*_finish++ = val;}}
}void push_back(const T& x)
{//扩容if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish++ = x;
}
注意:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。
1.4迭代器
所需要实现的迭代器其实很简单,对指针 typedef 即可
typedef T* iterator;
typedef const T* const_iterator;iterator begin() { return _start; }iterator end() { return _finish; }const_iterator begin()const { return _start; }const_iterator end()const { return _finish; }
实现了简单的迭代器,我们可以测试一下 迭代器遍历和范围for遍历
void test_vector1()
{vector<int> v;v.push_back(1);v.push_back(1);v.push_back(1);v.push_back(1);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << ' ';++it;}cout << endl;for (auto e : v){cout << e << ' ';}cout << endl;
}
这里我们为了后续方便封装一个打印函数
template<class T>
void print_vector(const vector<T>& v)
{vector<T>::const_iterator it = v.begin();while (it != v.end()){cout << *it << ' ';++it;}cout << endl;
}
可是这居然报错
为什么呢?没有实例化的类模板里面取东西,编译器是分不清 const_iterator 是静态成员变量还是类型的,在前面加一个 typename 显示告诉编译器是类型即可
template<class T>
void print_vector(const vector<T>& v)
{typename vector<T>::const_iterator it = v.begin();while (it != v.end()){cout << *it << ' ';++it;}cout << endl;
}
1.5增删查改
void insert(iterator pos, const T& x)
{if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish;while (pos < end){*end = *(end - 1);--end;}*pos = x;++_finish;
}
看起来没什么问题,但是存在着迭代器失效的风险

pos仍指向原来的空间!记录相对位置,修正一下pos即可
void insert(iterator pos, const T& x)
{if (_finish == _end_of_storage){size_t len = pos - _start;//记录相对位置reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish;while (pos < end){*end = *(end - 1);--end;}*pos = x;++_finish;
}
值得注意的是STL里的 insert有返回值!
这是为什么呢?还是防止迭代器失效的一种措施。
void test_vector2()
{vector<int>v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);print_vector(v);/* v.insert(v.begin() + 1, 10);print_vector(v);*/int x;cin >> x;// x==2auto pos = find(v.begin(), v.end(), x);//没找到返回 last 左闭右开区间if (pos != v.end()){v.insert(pos, 40);//pos 可以理解为下标位置 也可以理解为原来位置数据前面插入一个数据print_vector(v);(*pos) *= 10;//期望将x乘以10 但是是插入的40*10 并没有指向原来的数据//归为迭代器失效一类}print_vector(v);}

如果这里还发生了扩容呢??就是将push的5给删掉

这是什么鬼?我们不是已经修正了pos的位置吗?显然这里的p已经失效了!形参是无法改变实参的,我们修正了pos,但是影响不了p
传const 引用过去影响实参。但不是常量引用的话 ,下面代码会报错!
因为函数调用返回的参数是临时变量,且临时变量具有常性。
而事实上加了const引用里面的pos就无法修正了!我们的思路错了,STL的操作是加一个返回值 (返回的是新插入数据的下标)
iterator insert(iterator pos, const T& x)
{assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){size_t len = pos - _start;//记录相对位置reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish;while (pos < end){*end = *(end - 1);--end;}*pos = x;++_finish;return pos;
}

所以 insert后不能再访问find 的 p 想要访问得更新!
增删查改:
iterator insert(iterator pos, const T& x)
{assert(pos <= _finish && pos >= _start);if (_finish == _end_of_storage){size_t len = pos - _start;//记录相对位置reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish;while (pos < end){*end = *(end - 1);--end;}*pos = x;++_finish;return pos;
}iterator erase(iterator pos)
{assert(pos < _finish && pos >= _start);iterator it = pos + 1;while (it != end()){*(it - 1) = *it;++it;}--_finish;return pos;
}size_t find(T val = T())
{for (auto it = _start; it < _finish; it++){if (*it == val){return it - _start;}}return -1;
}T& operator[](size_t i)
{assert(i < size());return _start[i];
}const T& operator[](size_t i)const
{assert(i < size());return _start[i];
}void pop_back()
{assert(!empty());--_finish;
}
1.6模拟中的注意事项
- 规定:类模板在没有实例化时,迭代器无法读取!编译器不能区分这里const_iterator是类型还是静态成员变量。要想解决:第一可以在前面加上typename用来证明这里是类型;第二用auto,让编译器判断为类型

- 内置类型是没有构造函数的概念,但为了兼容模板(T val = T( ) ),可以被视为具有默认构造函数的行为
void reseize(size_t n, T val = T())//内置类型具有的构造析构等函数行为,并没有对应概念
{if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish < _start+n){*_finish++ = val;}}
}
- c++11中有强制生成默认构造的操作,即使类中已有其他构造函数,也能强制生成。eg:vector( ) = default

- 类里面可以用类名替代类型(特殊化),类外面规定:类名不能代表类型
//类里面可以用类名替代类型(特殊化)
//vector & operator=(vector v)
vector<T>& operator= (vector<T> v)
{swap(v);return *this;
}
- 类模板的成员函数,还可继续是函数模板
//类模板的成员函数还可以继续是函数模板
template<class InputIterator> //写成模板是为了兼容所有容器
vector(InputIterator first, InputIterator last)
{while(first != last){push_back(*first);++first;}
}
2、vector模拟补充
2.1迭代器区间构造问题
//C++11 强制生成默认构造
vector() = default;vector(size_t n, const T& val = T())
{reserve(n);for (size_t i; i < n; i++){push_back(val);}
}//类模板的成员函数还可以继续是函数模板
template<class InputIterator> //写成模板是为了兼容所有容器
vector(InputIterator first, InputIterator last)
{while(first != last){push_back(*first);++first;}
}
这个是对迭代器区间进行的构造函数,思路很简单,把迭代器区间的数据依次尾插就可以了(这里之所以另外使用一个新的模版,而不是使用vector类的模版,是为了兼容其他容器类型)。这样就可以通过一个现有的类型来构造容器。
但是出乎意料的是出现了一个问题: C2100 非法的间接寻址 (编译层面的问题) 。非法的间接寻址的造成原因有很多:
- 空指针引用:当一个指针没有被初始化或者为NULL时,对它进行间接寻址操作会导致非法访问。
- 野指针引用:当一个指针超出了它所指向的内存范围,或者已经被释放但仍然被引用时,进行间接寻址操作也会导致非法访问。
- 类型不匹配:如果试图将指针转换为不兼容的类型进行间接寻址,也会导致非法访问。

为什么报错在迭代器构造呢?因为编译器会寻找最合适的函数,但是这里与我们期望所违背!!
为了解决编译器选择的问题,可以多枚举几个构造函数:
vector(size_t n, const T& val = T())
{reserve(n);for (size_t i=0; i < n; i++){push_back(val);}
}vector(int n, const T& val = T())
{reserve(n);for (int i=0; i < n; i++){push_back(val);}
}
vector(long long n, const T&val = T())
{reserve(n);for (long long i=0; i < n; i++){push_back(val);}
}
这样可以做到优先匹配vector(int n,T val = T());,我们的问题也就解决了。
2.2memcpy深浅拷贝问题
我们测试一下自定义类型的vector(这里以string为例):
void vector_test6() {vector<string> v1;v1.push_back("11111");v1.push_back("22222");v1.push_back("33333");v1.push_back("44444");//再次插入扩容v1.push_back("55555");print_vector(v1);
}

程序崩溃了
分析:
<1> memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
<2> 如果拷贝的是内置类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。

结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃
解决方法:
void reserve(size_t n)
{if (n > capacity()){size_t old_size = size();T* tmp = new T[n];//memcpy(tmp, _start, size()*sizeof(T));//浅拷贝for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];//自定义类型的话 也是会调用自定义类型的赋值重载}delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = tmp + n;}
}
2.3动态二维数组的模拟及遍历
结构框架图:

//二维数组
vector<int>v(3, 1);
vector<vector<int>>vv(5, v);vv[2][1] = 2;
//与上述等价 vv.operator[](2).operator[](1) = 2;
for (size_t i = 0; i < vv.size(); i++)
{for (size_t j = 0; j < vv[i].size(); j++){cout << vv[i][j] << ' ';}cout << endl;
}
cout << endl;for (auto it = vv.begin(); it != vv.end(); it++)
{for (auto jt = (*it).begin(); jt != (*it).end(); jt++){cout << *jt << ' ';}cout << endl;
}
cout << endl;auto it1 = vv.begin();
/*auto it2 = (*it1).begin();*/
while (it1 != vv.end())
{auto it2 = (*it1).begin();//更新it2 指针在堆上分配,所以可以看见内存不是连续分配的while (it2 != (*it1).end()){cout << *it2 << ' ';it2++;}cout << endl;it1++;
}
cout << endl;for (auto row : vv)
{for (auto column : row){cout << column << ' ';}cout << endl;
}
cout << endl;
应用:杨辉三角
// 以杨慧三角的前n行为例:假设n为5
void test2vector(size_t n)
{// 使用vector定义二维数组vv,vv中的每个元素都是vector<int>vector<vector<int>> vv(n);// 将二维数组每一行中的vecotr<int>中的元素全部设置为1for (size_t i = 0; i < n; ++i)vv[i].resize(i + 1, 1);// 给杨慧三角出第一列和对角线的所有元素赋值for (int i = 2; i < n; ++i){for (int j = 1; j < i; ++j){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}
}
构造一个vv动态二维数组,vv中总共有n个元素,每个元素 都是vector类型的,每行没有包含任何元素,n为5时如下所示:

相关文章:
【C++】——vector深度剖析模拟实现
低头赶路,敬事如仪 目录 1、模拟vector 1.1底层结构 1.2构造析构 1.3尾插扩容 1.4迭代器 1.5增删查改 1.6模拟中的注意事项 2、vector模拟补充 2.1迭代器区间构造问题 2.2memcpy深浅拷贝问题 2.3动态二维数组的模拟及遍历 1、模拟vector 想要模拟实现自…...
OpenCV特征检测(11)从一组点中检测直线的函数
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在一组点中使用标准霍夫变换查找直线。 该函数使用霍夫变换的一种改进方法在一组点中查找直线。 HoughLinesPointSet 是 OpenCV 中的一个函数&a…...
C++_24_适配器
A 函数对象 概念: 重载函数调用运算符的类实例化的对象,就叫函数对象.又名仿函数,函数对象和()触发重载函数调用运算符的执行。 作用: 为算法提供策略 示例: #include <iostream> using namespace s…...
算法.图论-并查集
文章目录 1. 并查集介绍2. 并查集的实现2.1 实现逻辑2.2 isSameSet方法2.3 union方法(小挂大优化)2.4 find方法(路径压缩优化) 3. 并查集模板4. 并查集习题4.1 情侣牵手4.2 相似字符串组 1. 并查集介绍 定义: 并查集是一种树型的数据结构,用于处理一些不…...
elasticSearch常见命令及历史数据迁移
es这种非关系型数据库,感觉可视化效果不是很好,个人在操作中,习惯性通过简单的方式去访问。也是接触不久。只能出一些基操。共同学习记录,大家有好的操作也可留言备注。 1,常见命令 1)查询有哪些index&…...
WebLogic 漏洞复现
1、后台弱⼝令GetShell 默认账号密码:weblogic/Oracle123 weblogic常⽤弱⼝令:https://cirt.net/passwords?criteriaweblogic 这⾥注意, 单个账号错误密码5次之后就会⾃动锁定。 http://47.121.212.195:7001/console 2、登录后台后&#…...
web基础:域名、网页、HTML、web版本
文章目录 引言域名网站访问方式域名结构域名解析DNS解析过程 网页网页文件类型静态网页与动态网页常用动态网页编程语言 HTMLHTML 语法规则HTML 文件结构HTML 文件基本结构示例:常用 HTML 标签HTML文件基本结构 WEB版本 引言 web(World Wide Web&#x…...
【项目案例】物联网比较好的10+练手项目推荐,附项目文档/源码/视频
练手项目推荐 1 智能小车 项目功能介绍: 本项目由三部分组成:应用端(微信小程序)、设备端(Hi3861)、驱动端(UPS)。 1. 应用端,采用微信小程序作为应用端控制界面。在开…...
AWS注册时常见错误处理
引言 创建AWS账号是使用AWS云服务的第一步,但在注册过程中可能会遇到一些常见的问题。本文中九河云将帮助您排查和解决在创建AWS账户时可能遇到的一些常见问题,包括未接到验证电话、最大失败尝试次数错误以及账户激活延迟等。 常见问题及解决方法 1. …...
Spark-RDD持久化
一、Spark的三种持久化机制 1、cache 它是persist的一种简化方式,作用是将RDD缓存到内存中,以便后续快速访问,提高计算效率。cache操作是懒执行的,即执行action算子时才会触发。 2、persist 它提供了不同的存储级别࿰…...
vue2中使用tailwindCss 详细教程
1、先看官方文档:https://www.tailwindcss.cn/ 2、先安装:npm install -D tailwindcss ---------------通过 npm 安装 tailwindcss,然后创建你自己的 create your tailwind.config.js 配置文件。 npm install -D tailwindcss 3、初始化文件—npx tailwindcss init npx ta…...
机器视觉工程师一直做调试,维护岗位,想转岗软件方面C#从零开始,快则三年不到,慢则一辈子不会
其实不是每一家做视觉检测,或者是做设备必须要机器视觉工程师开发,其实公司对标准软件更感兴趣,主要非常高的性价比,省时省钱省人。所以这里有个问题,就是公司平台的重要性,首先他对开发是刚需,…...
【初阶数据结构】详解二叉树 - 树和二叉树(三)(递归的魅力时刻)
文章目录 前言1. 二叉树链式结构的意义2. 手搓一棵二叉树3. 二叉树的遍历(重要)3.1 遍历的规则3.2 先序遍历3.3 中序遍历3.4 后序遍历3.5 遍历的代码实现3.5.1 先序遍历代码实现3.5.2 中序遍历代码实现3.5.3 后序遍历代码实现 4. 统计二叉树结点的个数5.…...
【QT】QWidget 重要属性
文章目录 enabledgeometrywindowTitlewindowIconqrc 机制windowOpacitycursorfontQFont toolTip 和 toolTipDurationfocusPolicyQt::FocusPolicy styleSheet enabled 作用:设置控件是否可使用. true 表⽰可用, false 表⽰禁用. 对应的API bool isEnabled(); // 获…...
什么是数据库连接池?为什么需要使用连接池?
什么是数据库连接池?为什么需要使用连接池? 什么是数据库连接池? 数据库连接池是一种创建和管理数据库连接的技术。在传统的应用程序中,每当需要与数据库进行交互时,都会创建一个新的数据库连接。 这种做法虽然简单…...
2024ICPC网络赛第一场C. Permutation Counting 4(线性代数)
题目链接 题目大意:给你n个范围[ l i , r i l_i,r_i li,ri],每个位置可以在这个范围中选择一个数,然后形成排列1到n的排列p。问p的所有情况的个数的奇偶性。 一个很妙的行列式转化,纯纯的线性代数。 首先,我们把…...
01.前端面试题之ts:说说如何在Vue项目中应用TypeScript?
文章目录 一、前言二、使用Componentcomputed、data、methodspropswatchemit 三 、总结 一、前言 与link类似 在VUE项目中应用typescript,我们需要引入一个库vue-property-decorator, 其是基于vue-class-component库而来,这个库vue官方推出…...
【HTTP】方法(method)以及 GET 和 POST 的区别
文章目录 方法(method)登录上传GET 和 POST 有什么区别(面试)区别不准确的说法 方法(method) 首行中的第一部分。首行是由方法、URL 和版本号组成 方法描述了这次请求想干什么,最主要的是&…...
Ubuntu NFS 搭建及配置
在 Ubuntu 上搭建和配置 NFS(Network File System)服务器,可以让其他设备通过网络访问共享的文件夹。以下是步骤指南: 1. 安装 NFS 服务器 首先,安装 NFS 服务器软件包: sudo apt update sudo apt insta…...
双十一好物推荐,这些值得入手的宝藏产品
随着双十一的钟声即将敲响,这个万众期待的购物盛宴就要来临!为了让大家避免在众多的商品中不知所措,妮妮精心筹备了一份购物清单,分享那些我亲身感受超棒,觉得十分值得购买的物品。 这些商品不但价格合理,而…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...

