最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
C++11核心特性全解:从C++98到现代C++的全面升级(万字总结)
时间:2026-08-11 09:31:52 编辑:袖梨 来源:一聚教程网

一、C++11简介:为什么需要C++11?
C++11 是 C++ 的第⼆个主要版本,并且是从 C++98 起的最重要更新。它引⼊了⼤量更改,标准化了既
有实践,并改进了对 C++ 程序员可⽤的抽象。在它最终由 ISO 在 2011 年 8 ⽉ 12 ⽇采纳前,⼈们曾使
⽤名称“C++0x”,因为它曾被期待在 2010 年之前发布。C++03 与 C++11 期间花了 8 年时间,故⽽这
是迄今为⽌最⻓的版本间隔。从那时起,C++ 有规律地每 3 年更新⼀次。

稍作了解即可
C++11 是 C++ 发展史上第二个里程碑式的标准,也是自 C++98 发布以来最重要的一次版本更新。从 C++03 到 C++11 整整间隔了 8 年,这次更新不仅标准化了大量业界实践,还引入了移动语义、Lambda 表达式、可变参数模板、智能指针等一系列革命性特性,彻底改变了 C++ 的编程范式。从 C++11 开始,C++ 正式进入了「现代 C++」时代。
二、统一列表初始化 {}
其实一般情况下在学习的过程中我们小比特都有在用,这里性能优化有很大的方便性,减少了不必要的临时构造所产生的垃圾内存
1.1 C++98 的初始化痛点
C++98 中,{} 初始化只能用于数组和普通结构体,自定义类、容器都不能直接用列表初始化,初始化方式非常混乱。想要初始化一个带多个元素的 vector,只能先创建空对象,再一个个 push_back,代码繁琐且可读性差。
// ===== C++98 支持的初始化 =====int arr1[] = {1, 2, 3, 4, 5}; // 数组可以
int arr2[5] = {0}; // 数组可以
struct Point { int x; int y; };
Point p = {1, 2}; // 结构体可以
// ===== C++98 不支持的初始化 =====
// vector<int> v = {1,2,3}; // 编译报错:容器不能直接列表初始化
// Date d = {2025, 1, 1}; // 编译报错:自定义类不能直接列表初始化
1.2 C++11 统一列表初始化
C++11 扩大了 {} 的适用范围,所有内置类型、自定义类型、容器都可以用花括号进行初始化,并且可以省略赋值号 =,真正实现了「一套语法初始化所有对象」。
#include <iostream>#include <vector>
#include <string>
using namespace std;
class Date {
public:
Date(int year = 1, int month = 1, int day = 1)
: _year(year), _month(month), _day(day)
{
cout << "Date(int, int, int) 构造函数" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main() {
// 1. 内置类型初始化
int x1 = {2}; // 传统带=写法
int x2{2}; // C++11 新增:省略=的写法
// 2. 自定义类型初始化
// 底层原理:先用{2025,1,1}构造临时对象,再拷贝构造,编译器会优化为直接构造
Date d1 = {2025, 1, 1};
Date d2{2024, 7, 25}; // 省略=,更简洁
// 3. 容器初始化 + 容器插入,便利性大幅提升
vector<int> v1 = {1, 2, 3, 4, 5}; // 直接批量初始化容器
vector<Date> v2;
v2.push_back({2025, 1, 1}); // 不用写匿名对象,直接传构造参数
return 0;
}
相比 C++98 的优势:
统一了所有类型的初始化语法,不用再记忆不同类型的初始化规则
容器插入多参数对象时代码更简洁,减少冗余的匿名对象写法
1.3 底层支撑:std::initializer_list
容器之所以能支持 {1,2,3,4,5} 这种批量初始化,本质是因为 C++11 为所有 STL 容器新增了 std::initializer_list 版本的构造函数和赋值函数。
std::initializer_list 是一个轻量级的类,底层对应一段连续的常量数组,内部用两个指针指向数组首尾。它可以自动接收 {…} 形式的初始化列表,支持迭代器遍历。
#include <initializer_list>#include <iostream>
using namespace std;
// 模拟 vector 支持 initializer_list 构造与赋值
template<class T>
class my_vector {
public:
typedef T* iterator;
// initializer_list 构造函数:接收{}列表,逐个插入
my_vector(initializer_list<T> il) {
for (auto e : il) {
push_back(e);
}
}
// initializer_list 版本的赋值重载
my_vector& operator=(initializer_list<T> il) {
clear();
for (auto e : il) {
push_back(e);
}
return *this;
}
void push_back(const T& val) { /* 尾插实现省略 */ }
void clear() { /* 清空实现省略 */ }
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _endofstorage = nullptr;
};
int main() {
my_vector<int> v = {1,2,3,4,5}; // 自动调用 initializer_list 构造
v = {10,20,30,40,50}; // 自动调用 initializer_list 赋值
// 实际STL用法:map也支持initializer_list初始化
map<string, string> dict = {
{"sort", "排序"},
{"string", "字符串"},
{"insert", "插入"}
};
return 0;
}
使用场景:批量初始化容器、批量赋值、容器插入多元素时,用 initializer_list 语法最简洁直观。
二、右值引用与移动语义:从根源减少拷贝开销
右值引用是 C++11 最核心的性能优化特性,它彻底解决了 C++98 中深拷贝带来的不必要性能损耗,是现代 C++ 效率提升的关键。
2.1 先搞懂:左值和右值
区分左值和右值的核心标准:能不能取地址。
左值(lvalue):有持久存储状态、可以取地址的对象。比如普通变量、指针解引用、数组元素等。左值可以出现在赋值号左边或右边。
右值(rvalue):临时的、无法取地址的对象。比如字面常量、表达式结果、匿名临时对象等。右值只能出现在赋值号右边。
int main() {// ===== 左值:可以取地址 =====
int a = 10;
int* p = new int(0);
string s("hello");
&a; &p; &s; // 都能取地址,都是左值
// ===== 右值:不能取地址 =====
10; // 字面常量
a + 1; // 表达式计算结果
string("hi");// 匿名临时对象
// &10; &(a+1); &string("hi"); // 编译报错:右值无法取地址
return 0;
}
2.2 左值引用 vs 右值引用
C++98 只有左值引用(Type&),C++11 新增右值引用(Type&&),二者本质都是给对象取别名,底层都是用指针实现。
int main() {int a = 10;
// 左值引用:只能引用左值
int& r1 = a;
// int& r2 = 10; // 报错:左值引用不能直接绑定右值
// const 左值引用:左值右值都能绑定,但不能修改对象
const int& cr1 = a;
const int& cr2 = 10;
// 右值引用:只能绑定右值
int&& rr1 = 10;
int&& rr2 = a + 1;
// int&& rr3 = a; // 报错:右值引用不能直接绑定左值
// std::move:将左值强制转为右值,让右值引用可以绑定
int&& rr4 = move(a);
// 重要细节:右值引用变量本身是左值(可以取地址)
&rr1; // 合法,rr1是变量,是左值
// int&& rr5 = rr1; // 报错:rr1是左值,不能绑定右值引用
int&& rr5 = move(rr1); // 必须再move一次才能继续绑定右值引用
return 0;
}
2.3 移动构造与移动赋值:窃取资源代替深拷贝
C++98 中,类的拷贝构造和拷贝赋值都是深拷贝,对于 string、vector 这种管理堆资源的类,拷贝时需要重新申请内存、拷贝数据,代价非常大。
C++11 新增移动构造和移动赋值:参数是右值引用,本质是「窃取」临时对象 / 将亡对象的资源,不用重新申请内存、拷贝数据,性能提升显著。
下面以自定义 string 为例,完整对比拷贝与移动的实现:
#include <iostream>#include <string.h>
#include <algorithm>
using namespace std;
namespace bit {
class string {
public:
// 普通构造函数
string(const char* str = "")
: _size(strlen(str))
, _capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, str);
cout << "string(const char*) -- 普通构造" << endl;
}
// ===== C++98 就有:拷贝构造(深拷贝,代价大)=====
string(const string& s)
: _size(s._size)
, _capacity(s._capacity)
{
_str = new char[_capacity + 1];
strcpy(_str, s._str);
cout << "string(const string&) -- 拷贝构造【深拷贝,O(n)开销】" << endl;
}
// ===== C++11 新增:移动构造(交换资源,代价极小)=====
// 参数是右值引用,接收临时对象/将亡对象
string(string&& s)
: _str(nullptr)
, _size(0)
, _capacity(0)
{
// 直接交换资源,把s的内存偷过来,不用深拷贝
swap(s);
cout << "string(string&&) -- 移动构造【交换指针,O(1)开销】" << endl;
}
// ===== C++98 就有:拷贝赋值(深拷贝)=====
string& operator=(const string& s) {
if (this != &s) {
char* tmp = new char[s._capacity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
_size = s._size;
_capacity = s._capacity;
}
cout << "string& operator=(const string&) -- 拷贝赋值" << endl;
return *this;
}
// ===== C++11 新增:移动赋值=====
string& operator=(string&& s) {
if (this != &s) {
swap(s); // 交换资源
}
cout << "string& operator=(string&&) -- 移动赋值" << endl;
return *this;
}
// 交换成员
void swap(string& s) {
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
~string() {
delete[] _str;
_str = nullptr;
}
const char* c_str() const { return _str; }
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
};
}
场景 1:用临时对象初始化
int main() {bit::string s1("hello");
// 用左值s1初始化s2 → 调用拷贝构造(深拷贝,完整复制数据)
bit::string s2 = s1;
// 用匿名临时对象初始化s3 → 调用移动构造(交换指针,零深拷贝)
bit::string s3 = bit::string("world");
// 用move后的左值初始化s4 → 调用移动构造(s1的资源被转移,变成空串)
bit::string s4 = move(s1);
return 0;
}
场景 2:函数传值返回(最常用的性能优化场景)
C++98 中,函数返回局部对象时,会发生两次深拷贝(局部对象→临时对象→接收对象),即使编译器优化也至少有一次深拷贝。
有了移动语义后,返回局部对象会自动调用移动构造,几乎零开销,再也不用靠输出型参数规避拷贝了。
bit::string addStrings(bit::string num1, bit::string num2) {bit::string str;
// ... 省略字符串相加逻辑 ...
return str; // str是局部对象,出作用域就销毁,属于将亡值
}
int main() {
// C++98:至少1次深拷贝,大对象性能损耗严重
// C++11:自动调用移动构造,只交换指针,性能大幅提升
bit::string ret = addStrings("111", "222");
return 0;
}
相比 C++98 的优势:
对于管理堆内存的类(string、vector、map 等),移动语义将拷贝的 O (n) 开销降为 O (1)
函数返回大对象时,不再需要用输出型参数规避拷贝,代码更优雅自然
2.4 引用折叠与万能引用
模板中的 T&& 不总是右值引用,它会根据实参的类型发生引用折叠:
传入左值 → T 推导为 int& → int& && 折叠为 int&(左值引用)
传入右值 → T 推导为 int → int&& 就是右值引用
这种既能接收左值又能接收右值的模板参数,叫做万能引用(Universal Reference)。
// 万能引用模板:传左值实例化为左值引用,传右值实例化为右值引用template<class T>
void Func(T&& t) {
// ...
}
int main() {
int a = 10;
Func(a); // 左值 → T=int& → t是int&类型
Func(10); // 右值 → T=int → t是int&&类型
return 0;
}
2.5 完美转发:保持参数的值属性
万能引用有个问题:右值引用变量本身是左值,把它传给下一层函数时,会丢失右值属性,永远匹配左值引用版本。
完美转发 std::forward 可以保持参数原本的左 / 右值属性:左值传进去还是左值,右值传进去还是右值。
#include <iostream>#include <utility>
using namespace std;
void Fun(int& x) { cout << "左值引用重载" << endl; }
void Fun(const int& x) { cout << "const 左值引用重载" << endl; }
void Fun(int&& x) { cout << "右值引用重载" << endl; }
template<class T>
void Function(T&& t) {
// Fun(t); // 永远调用左值版本,因为t是变量,表达式属性是左值
Fun(forward<T>(t)); // 完美转发:保持t原本的左右值属性
}
int main() {
int a = 10;
Function(a); // 实参是左值 → 调用左值版本
Function(10); // 实参是右值 → 调用右值版本
Function(move(a)); // 实参是右值 → 调用右值版本
return 0;
}
使用场景:写模板函数、封装接口时,需要把参数原封不动地转发给下层函数,就用完美转发。
三、可变参数模板:让参数数量和类型都能泛化
C++98 的模板只能固定参数个数,C++11 新增可变参数模板,支持任意个数、任意类型的参数,是 STL emplace 系列接口的底层支撑。
3.1 基本语法
用 … 表示参数包:
class… Args:模板参数包,表示 0 个或多个类型
Args… args:函数参数包,表示 0 个或多个参数对象
#include <iostream>using namespace std;
// sizeof... 计算参数包中参数的个数
template<class ...Args>
void Print(Args... args) {
cout << "参数包个数:" << sizeof...(args) << endl;
}
int main() {
Print(); // 0个参数
Print(1); // 1个参数
Print(1, string("hi")); // 2个参数
Print(1, "hello", 2.2); // 3个参数
return 0;
}
3.2 参数包的展开:递归方式
可变参数包不能直接遍历,通常用递归方式逐层展开:先取出第一个参数处理,剩下的参数包继续递归,直到参数包为空匹配终止函数。
#include <iostream>#include <string>
using namespace std;
// 递归终止函数:参数包为空时调用
void ShowList() {
cout << endl;
}
// 递归展开函数:取出第一个参数val,剩下的args继续递归
template<class T, class ...Args>
void ShowList(T val, Args... args) {
cout << val << " ";
ShowList(args...); // 剩下的参数包继续传递
}
template<class ...Args>
void Print(Args... args) {
ShowList(args...);
}
int main() {
Print(1, "hello", 2.2, 'a'); // 输出:1 hello 2.2 a
return 0;
}
编译时编译器会自动推导出对应参数个数的函数,本质还是生成多个重载函数。
3.3 实际应用:emplace 系列接口
C++11 为所有 STL 容器新增了 emplace_back、emplace 接口,底层就是可变参数模板 + 完美转发。
相比 push_back,emplace 可以直接把构造参数传给元素的构造函数,在容器节点上直接构造对象,减少一次拷贝 / 移动开销。
#include <list>int main() {
list<bit::string> lt;
bit::string s1("hello");
// 1. 传左值 → 和push_back效果一致,调用拷贝构造
lt.emplace_back(s1);
// 2. 传右值 → 和push_back效果一致,调用移动构造
lt.emplace_back(move(s1));
// 3. 直接传构造参数 → 在节点上直接构造,连移动都省了!
// 这是push_back做不到的,也是emplace最大的优势
lt.emplace_back("world");
list<pair<bit::string, int>> lt2;
// 直接传pair的构造参数,不用先构造pair对象再插入
lt2.emplace_back("苹果", 5);
return 0;
}
优势:
减少了一次临时对象的构造 + 析构,性能更优
日常开发推荐优先用 emplace 替代 push/insert
四、类的新功能:更灵活的默认函数控制
4.1 默认生成的移动构造和移动赋值
C++98 类有 4 个默认成员函数(构造、析构、拷贝构造、拷贝赋值),C++11 新增 2 个:移动构造、移动赋值。
编译器自动生成默认移动构造 / 赋值的条件:
你没有自己实现移动构造、移动赋值
你也没有自己实现析构函数、拷贝构造、拷贝赋值
默认生成的移动构造:内置类型逐字节拷贝,自定义类型调用它的移动构造(没有就调用拷贝构造)
4.2 default 与 delete
= default:显式要求编译器生成默认版本的函数
= delete:禁止编译器生成该函数,比 C++98 设为 private 更简洁直观
class Person {public:
Person(const char* name = "", int age = 0)
: _name(name), _age(age)
{}
// 自己写了拷贝构造,编译器就不会自动生成移动构造
Person(const Person& p)
: _name(p._name), _age(p._age)
{}
// 显式要求编译器生成默认版本的移动构造
Person(Person&& p) = default;
// 禁止拷贝赋值(C++11 写法,比C++98设private更清晰)
Person& operator=(const Person& p) = delete;
private:
bit::string _name;
int _age;
};
4.3 成员变量缺省值
C++11 允许在类内声明成员变量时直接给默认值,如果初始化列表没有显式初始化该成员,就会使用这个缺省值。
class A {private:
// 声明时直接给缺省值
int _a = 0;
int* _p = nullptr;
bit::string _s = "default";
};
五、STL 的变化:新容器与新接口
5.1 新增容器
5.2 新增通用接口
所有容器都新增了右值引用版本的 push/insert、移动构造、移动赋值
所有容器都新增了 initializer_list 版本的构造和赋值
新增 emplace / emplace_back 系列接口
支持范围 for 遍历(底层封装迭代器,语法更简洁)
六、Lambda 表达式:写匿名函数的利器
6.1 为什么需要 Lambda
C++98 中,如果想给算法传一个比较规则,要么用函数指针,要么写仿函数类。仿函数需要单独定义类,代码分散、非常繁琐。
C++11 的 Lambda 表达式可以在函数内部定义匿名函数对象,写起来灵活轻便,是 STL 算法的最佳搭档。
6.2 语法格式+例子
[捕捉列表]:捕获外层作用域的变量供 Lambda 内部使用,不能为空
(参数列表):和普通函数参数一样,没有参数可以省略 ()
mutable:取消值捕捉的 const 属性,让值捕捉的变量可以修改
-> 返回值类型:追踪返回类型,一般可以省略,编译器自动推导
{函数体}:实现逻辑,不能为空
[捕捉列表] (参数列表) mutable -> 返回值类型 { 函数体 }int main() {
int a = 0, b = 1, c = 2, d = 3;
// 1. 值捕捉a,引用捕捉b
auto func1 = [a, &b]() {
// a++; // 报错:值捕捉的变量默认是const的,不能修改
b++; // 引用捕捉可以修改,直接影响外面的b
return a + b;
};
cout << func1() << endl;
// 2. 加mutable:值捕捉的变量也能改(改的是内部拷贝,不影响外面)
auto func2 = [=]() mutable {
a++; b++; c++;
return a + b + c;
};
cout << func2() << endl;
// 3. 隐式引用捕捉:所有用到的变量都引用捕捉
auto func3 = [&]() {
a++; b++; c++; d++; // 都能改,都影响外部变量
};
func3();
return 0;
}
6.4 典型应用:sort 自定义排序
C++98 要为每种排序规则写一个仿函数类,C++11 直接写 Lambda 即可,代码集中、可读性强。
#include <vector>#include <algorithm>
#include <string>
using namespace std;
struct Goods {
string _name;
double _price;
int _evaluate;
Goods(const char* name, double price, int evaluate)
: _name(name), _price(price), _evaluate(evaluate)
{}
};
int main() {
vector<Goods> v = {
{"苹果", 2.1, 5},
{"香蕉", 3.0, 4},
{"橙子", 2.2, 3},
{"菠萝", 1.5, 4}
};
// 按价格升序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._price < g2._price;
});
// 按评价降序
sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
return g1._evaluate > g2._evaluate;
});
return 0;
}
6.5 Lambda 底层原理
Lambda 本质就是仿函数:编译器会为每个 Lambda 生成一个唯一的匿名类,重载了 operator()。捕捉列表的变量就是这个类的成员变量,构造 Lambda 对象时把捕捉的变量初始化进去。
所以 Lambda 对象的大小、行为和仿函数完全一致,只是语法更简洁。
七、包装器 function 与 bind:统一可调用对象
7.1 std::function:统一类型
C++ 中可调用对象有很多种:普通函数、仿函数、Lambda、成员函数…… 它们类型各不相同,无法统一管理。
std::function 是一个包装器,可以把所有签名相同的可调用对象包装成同一个类型,方便统一存储、传递和管理。
头文件:
#include <functional>#include <iostream>
#include <string>
using namespace std;
// 普通函数
int add(int a, int b) { return a + b; }
// 仿函数
struct Add {
int operator()(int a, int b) { return a + b; }
};
class Calc {
public:
static int plus_static(int a, int b) { return a + b; } // 静态成员函数
int plus_normal(int a, int b) { return a + b; } // 普通成员函数
};
int main() {
// 包装普通函数
function<int(int, int)> f1 = add;
// 包装仿函数
function<int(int, int)> f2 = Add();
// 包装Lambda
function<int(int, int)> f3 = [](int a, int b) { return a + b; };
// 包装静态成员函数
function<int(int, int)> f4 = &Calc::plus_static;
// 包装普通成员函数(需要绑定对象)
Calc c;
function<int(int, int)> f5 = bind(&Calc::plus_normal, &c, placeholders::_1, placeholders::_2);
cout << f1(1, 2) << endl;
cout << f2(1, 2) << endl;
cout << f3(1, 2) << endl;
return 0;
}
经典应用:命令映射表
用 map + function 实现字符串到函数的映射,替代冗长的 switch-case,扩展性极强,符合开闭原则。
// LeetCode 150. 逆波兰表达式求值#include <vector>
#include <stack>
#include <map>
#include <functional>
#include <string>
using namespace std;
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
// 用map映射操作符和对应的运算函数
map<string, function<int(int, int)>> opMap = {
{"+", [](int x, int y) { return x + y; }},
{"-", [](int x, int y) { return x - y; }},
{"*", [](int x, int y) { return x * y; }},
{"/", [](int x, int y) { return x / y; }}
};
for (auto& s : tokens) {
if (opMap.count(s)) {
int right = st.top(); st.pop();
int left = st.top(); st.pop();
st.push(opMap[s](left, right));
} else {
st.push(stoi(s));
}
}
return st.top();
}
};
优势:新增运算只需要在 map 里加一行映射,不用修改核心逻辑,扩展性远优于 switch。
7.2 std::bind:调整参数
std::bind 是函数适配器,可以调整可调用对象的参数个数、参数顺序,还能绑死固定参数。
占位符 placeholders::_1、_2 表示新函数的第 1、2 个参数。
#include <functional>#include <iostream>
using namespace std;
using namespace placeholders;
int Sub(int a, int b) {
return (a - b) * 10;
}
int main() {
// 1. 原封不动包装
auto sub1 = bind(Sub, _1, _2);
cout << sub1(10, 5) << endl; // 输出50
// 2. 调换参数顺序
auto sub2 = bind(Sub, _2, _1);
cout << sub2(10, 5) << endl; // 输出-50
// 3. 绑死第一个参数,只留一个参数
auto sub3 = bind(Sub, 100, _1);
cout << sub3(5) << endl; // 输出950
return 0;
}
使用场景:函数参数太多、需要固定部分参数简化调用时,用 bind 非常方便。
八、其他重要特性
8.1 智能指针
C++11 新增了 unique_ptr、shared_ptr、weak_ptr 三大智能指针,利用 RAII 机制自动管理堆内存,从根源解决内存泄漏问题。这部分内容较多,通常单独成章深入讲解。
8.2 constexpr 常量表达式
让函数、变量在编译期就能计算出结果,将运行时开销转移到编译期,提升程序运行性能。
8.3 范围 for
底层封装迭代器,让容器遍历更简洁直观
vector<int> v = {1,2,3,4,5};for (auto e : v) { // 自动遍历所有元素
cout << e << " ";
}
九、总结
C++11 不是简单的语法糖堆砌,而是一次全方位的革命性升级:
性能层面:移动语义从根源减少了深拷贝开销,让 C++ 程序性能再上一个台阶
开发效率层面:列表初始化、Lambda、可变参数模板、范围 for 等特性,大幅简化了代码,提升了开发效率
安全层面:智能指针解决了内存泄漏难题,=delete 等语法让类的设计更安全
泛型能力层面:可变参数模板、完美转发让泛型编程更灵活、更强大
掌握了 C++11,才算真正踏入现代 C++ 的大门。后续的 C++14/17/20 都是在这个基础上的迭代和完善。

相关文章
- 突发,Claude首破黎曼猜想新纪录! 08-11
- 秋蝉漫画免费漫画页面-秋蝉韩漫sss级在线观看入口地址 08-11
- 无畏契约官网入口在哪里-官网入口地址分享 08-11
- 抖音怎么修改收货地址 08-11
- 一年最高1499元,千问推出付费版 08-11
- 微软计划最快9月发布其下一代MAIA 300人工智能芯片 08-11