跨越十年的C++演进:C++11新特性全解析
liuian 2025-07-07 20:10 88 浏览
原作者:Linux教程,原文「链接」:
https://mp.weixin.qq.com/s/oFbiFlqiwgVcJIMMvTelEA
很多刚刚进入 C++ 领域的朋友,最初是从 C 语言转过来的。因此在编写 C++ 代码时,往往会不自觉地延续 C 的语法风格和编程思维。
然而,随着 C++ 的不断演进,特别是从 C++11 开始,这门语言在语法特性和编程范式上发生了显著变化。许多新特性不仅提升了代码的安全性与可读性,也极大地增强了开发效率。
最近也有朋友和我聊到,现在的 C++ 看起来越来越“陌生”,有些语法甚至已经看不懂了。这也说明了了解现代 C++ 的重要性。
因此,对于刚接触 C++ 的新手来说,非常有必要对现代 C++ 的发展有一个整体的认识。今天我们就从现代化 C++ 的起点 —— C++11 标准 开始,一起聊聊它引入了哪些实用且重要的新特性。
跨越十年的C++演进系列,分为5篇,本文为第一篇,后续会持续更新C++14、C++17、C++20、C++23~
C++11 简介
C++11(也被称为 C++0x)是 C++ 编程语言的一个重大更新版本,于 2011 年正式发布。它是对 C++98/03 的一次全面升级,标志着现代 C++ 的开端。
该标准在原有基础上引入了约 140 个新特性,并修正了大约 600 个已知的语言缺陷。这些改进使得 C++ 更加简洁、安全、高效,同时也为后续的标准(如 C++14、C++17、C++20 等)奠定了坚实的基础。
接下来的内容中,将详细介绍 C++11 中一些具有代表性的新特性,并通过实际代码示例帮助你更好地理解和使用这些特性。
1. 统一初始化(Uniform Initialization)
为了解决 C++ 中多种初始化语法带来的歧义和复杂性,C++11 引入了统一初始化(Uniform Initialization)机制,使用 花括号 {} 作为通用的初始化语法。
这种初始化方式具有以下优势:
- 语法统一
- :无论是基本类型、类对象、数组还是容器,都可以使用 {} 初始化。
- 避免歧义
- :消除了“最令人烦恼的解析”问题(most vexing parse)。
- 安全性更高
- :防止窄化转换(narrowing conversion),编译器会在可能丢失精度时报错。
示例代码:
#include <iostream>
class Foo {
public:
Foo(int) {
std::cout << "Foo constructed with int\n";
}
private:
Foo(const Foo&); // 私有拷贝构造函数,禁止拷贝
};
int main() {
Foo a1(123); // 直接调用构造函数,合法
// Foo a2 = 123; // 错误!会尝试隐式调用拷贝构造函数,但该函数是私有的
Foo a3 = {123}; // 合法!列表初始化,直接调用构造函数
Foo a4{123}; // 合法!另一种写法,等效于上一行
int a5 = {3}; // 基本类型初始化,合法
int a6{3}; // 另一种写法,同样合法
return 0;
}输出结果:
Foo constructed with int
Foo constructed with int
Foo constructed with int说明:
- a1(123)
- 是传统的直接调用构造函数的方式。
- a2 = 123
- 被注释掉是因为它试图通过隐式转换构造一个临时对象,再调用拷贝构造函数来初始化 a2,但由于拷贝构造函数是私有的,所以会报错。
- a3 = {123}
- 和 a4{123} 都使用了统一初始化语法,它们都直接调用了接受 int 的构造函数,不会涉及拷贝构造,因此可以通过编译。
- 对于基本数据类型如 int,也可以使用 {} 进行初始化,增强了语法一致性。
2. auto类型推导(Type Deduction with auto)
在 C++ 程序开发中,为了提升代码的安全性和可读性,通常建议在定义变量时立即进行初始化。特别是在使用指针时,如果指向不明确,容易产生野指针,从而引发程序异常。
C++11 引入了关键字 auto,它允许编译器根据变量的初始化表达式自动推导其类型。这一特性不仅简化了复杂类型的书写,也提升了代码的可维护性。
使用优势:
- 简化复杂类型声明
- :尤其是嵌套模板类型。
- 增强可读性
- :避免冗长的类型书写。
- 提高安全性
- :强制要求变量必须初始化(否则无法推导类型)。
示例代码:
#include <iostream>
#include <vector>
int main() {
// 定义一个二维向量
std::vector<std::vector<int>> v = {{1, 2, 3}, {4, 5, 6}};
// 传统方式:手动指定迭代器类型
std::vector<std::vector<int>>::iterator it = v.begin();
// 使用 auto:让编译器自动推导类型
auto it_auto = v.begin(); // 更简洁且易读
// 遍历第一个子向量并输出
for (auto inner : *it_auto) {
std::cout << inner << " "; // 输出: 1 2 3
}
std::cout << std::endl;
// 基本数据类型也能自动推导
auto x = 5; // 推导为 int
auto y = 3.14; // 推导为 double
return 0;
}输出结果:
1 2 3说明:
- std::vector<std::vector<int>>::iterator
- 是一个较长的类型名,使用 auto 可以显著减少冗余代码。
- 在 for 循环中,auto inner 自动推导出 inner 的类型为 int,使代码更加简洁。
- 对于基本类型如 x 和 y,auto 同样能够正确地根据初始化值推导出对应的类型。
注意事项:
- auto
- 必须结合初始化表达式使用,否则会编译失败。
- 尽管 auto 提高了可读性,但过度使用可能导致类型不够直观,应根据实际场景合理使用。
3. nullptr—— 空指针的新代表
在 C++11 中,引入了新的关键字 nullptr,用于替代旧版 C++(C++98/03)中的宏定义 NULL。
nullptr 的类型是 std::nullptr_t,它是一个专门表示空指针的字面量,能更明确地表达“空指针”的语义,避免了一些潜在的类型歧义问题。
使用 nullptr的优势:
- 类型安全更高
- :nullptr 不是整数,也不是宏,而是专为空指针设计的类型。
- 避免函数重载歧义
- :尤其在函数重载时,使用 nullptr 可以明确匹配到期望的指针类型。
- 可读性更强
- :一看便知是空指针,而不是一个值为 0 的整数。
示例代码:
#include <iostream>
// 函数重载示例
void foo(int i) {
std::cout << "foo_int" << std::endl;
}
void foo(char* pc) {
std::cout << "foo_char*" << std::endl;
}
int main() {
// foo(NULL); // 错误!编译器无法确定调用哪一个函数,存在歧义
foo(nullptr); // 正确!明确调用 foo(char*),因为 nullptr 是指针类型
return 0;
}输出结果:
foo_char*- 在旧版 C++ 中,NULL 通常被定义为 (void*)0 或者直接是整数字面量 0,这会导致在函数重载时难以判断应匹配哪个函数。
- 使用 nullptr 后,编译器能够准确识别出它是一个空指针常量,从而正确匹配到接受指针参数的函数。
- 在实际开发中,建议在定义指针时就进行初始化,若指向不明确,则使用 nullptr 初始化,以避免野指针带来的运行时错误。
4. enum class—— 强类型枚举
在 C++11 中引入了 enum class,也称为强类型枚举(scoped enumeration),它解决了传统枚举(enum)存在的一些问题,如命名冲突和隐式类型转换。
使用 enum class的优势:
- 作用域限制
- :枚举值被限定在枚举类型的作用域内,避免全局命名污染。
- 类型安全增强
- :不能隐式转换为整型或其他枚举类型,提升代码安全性。
- 可读性更高
- :通过作用域访问枚举值,使代码意图更清晰。
示例代码:
#include <iostream>
// 定义两个强类型枚举
enum class Apple { green, red };
enum class Orange { big, small };
int main() {
// 使用作用域访问枚举值
Apple a = Apple::green;
Orange o = Orange::big;
// 尝试比较不同类型的枚举值
if (a == o) {
std::cout << "绿苹果 = 大橘子" << std::endl;
} else {
std::cout << "绿苹果 != 大橘子" << std::endl;
}
return 0;
}- 在传统 enum 中,Apple::green 和 Orange::big 都会被隐式转换为整数 0,从而导致它们“相等”,这显然不符合语义。
- 使用 enum class 后,每个枚举都是独立的类型,即使它们的值相同,也不能直接比较或混用。
- 编译器会阻止这种不合理的比较,除非你显式地使用 static_cast 进行类型转换。
如何进行显式转换?
如果你确实需要将 enum class 值转换为整数,可以使用 static_cast:
int appleValue = static_cast<int>(Apple::green); // 正确:appleValue = 0注意:
- 推荐优先使用 enum class 而不是传统 enum,特别是在大型项目中。
- enum class
- 的枚举值不会自动暴露到外层作用域,必须通过 枚举名::值 的方式访问。
- 可以指定底层类型(如 enum class Color : uint8_t),进一步控制内存占用。
5. Lambda 表达式
Lambda 表达式是C++11最重要也是最常用的特性之一。它允许我们在代码中就地定义匿名函数对象,极大提升了代码的简洁性和可读性。
特别是在使用标准库算法时,lambda 表达式常常能避免定义额外的函数或函数对象,使逻辑更加紧凑、直观。
Lambda 表达式的优点:
- 声明式编程风格
- :可以在需要的地方直接定义功能逻辑,无需单独编写命名函数。
- 代码简洁高效
- :减少冗余代码,提高开发效率。
- 支持闭包机制
- :能够捕获上下文变量,实现灵活的功能封装和状态传递
示例代码:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用 lambda 表达式作为比较函数进行排序(升序)
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
// 输出排序后的结果
for (auto number : numbers) {
std::cout << number << " ";
}
std::cout << std::endl;
return 0;
}在使用 Lambda 表达式时,捕获列表(Capture List) 决定了 Lambda 是否以及如何访问其定义所在作用域中的变量。
默认情况下,Lambda 表达式无法修改通过值捕获的外部变量,因为这些变量是以副本的形式被捕获的,并且在 Lambda 函数体内被视为 const 类型。
捕获方式 | 含义 |
[] | 不捕获任何外部变量 |
[x] | 以值的方式捕获变量 x |
[&x] | 以引用的方式捕获变量 x |
[=] | 以值的方式捕获所有使用的外部变量(隐式捕获) |
[&] | 以引用的方式捕获所有使用的外部变量(隐式捕获) |
[this] | 捕获当前类对象的 this 指针,允许访问成员变量和函数 |
6. 智能指针
在 C++ 中,没有自动垃圾回收机制,因此开发者必须手动管理动态分配的内存。如果忘记释放不再使用的内存,就可能导致内存泄漏;而如果访问了已经被释放的内存,则可能引发悬空指针问题。
为了解决这些问题,C++11 引入了智能指针(Smart Pointers),作为资源管理的重要工具。它们通过 RAII(Resource Acquisition Is Initialization)机制,确保内存资源在对象生命周期结束时被自动释放,从而大大提升代码的安全性和可维护性。
C++11 提供了三种主要的智能指针类型:
- std::unique_ptr:独占式智能指针,不能复制,但可以移动,表示某个资源只能由一个指针拥有所有权。
- std::shared_ptr:共享式智能指针,多个智能指针可以共同拥有同一个资源,内部使用引用计数管理资源生命周期。
- std::weak_ptr:弱引用智能指针,不控制资源的生命周期,通常配合 shared_ptr 使用,用来解决循环引用问题。
6.1、std::unique_ptr
- 表示对资源的唯一拥有权。
- 不允许拷贝构造和赋值操作(即不能复制),但可以通过 std::move() 转移所有权。
- 适用于资源不需要共享的场景。
示例:
#include <iostream>
#include <memory>
int main() {
// 创建 unique_ptr 管理一个堆上的整数
std::unique_ptr<int> ptr(new int(42));
std::cout << "ptr value: " << *ptr << std::endl;
// 无法复制
// std::unique_ptr<int> ptr2 = ptr; // 编译错误
// 可以转移所有权
std::unique_ptr<int> ptr2 = std::move(ptr);
if (ptr == nullptr) {
std::cout << "ptr is now null" << std::endl;
}
return 0;
}6.2、std::shared_ptr
- 多个 shared_ptr 实例可以指向同一块资源。
- 内部使用引用计数来跟踪有多少个 shared_ptr 正在使用该资源。
- 当最后一个 shared_ptr 被销毁时,资源会被自动释放。
示例:
#include <iostream>
#include <memory>
int main() {
// 创建 shared_ptr 管理一个堆上的整数
std::shared_ptr<int> ptr1 = std::make_shared<int>(100);
{
std::shared_ptr<int> ptr2 = ptr1; // 共享所有权
std::cout << "Use count inside block: " << ptr1.use_count() << std::endl; // 输出 2
} // ptr2 离开作用域,引用计数减1
std::cout << "Use count outside block: " << ptr1.use_count() << std::endl; // 输出 1
return 0;
}6.3、std::weak_ptr
- 是一种观察者角色,它不会增加引用计数。
- 常用于避免 shared_ptr 之间的循环引用问题。
- 不能直接访问所指向的对象,必须先通过 lock() 获取一个 shared_ptr。
示例:
#include <iostream>
#include <memory>
struct A;
struct B;
struct A {
std::shared_ptr<B> b_ptr;
~A() { std::cout << "A destroyed\n"; }
};
struct B {
std::weak_ptr<A> a_ptr; // 使用 weak_ptr 避免循环引用
~B() { std::cout << "B destroyed\n"; }
};
int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->b_ptr = b;
b->a_ptr = a;
return 0;
} // a 和 b 被正确析构,不会有内存泄漏- 推荐优先使用 std::make_shared<T>() 或 std::make_unique<T>() 来创建智能指针,这样更安全且效率更高。
- 避免裸指针(raw pointer)直接操作堆内存,尽量用智能指针封装资源管理逻辑。
- 在多线程环境下,shared_ptr 的引用计数是线程安全的,但其指向的对象并非线程安全,仍需同步保护。
7. 并发支持
C++11 标准首次在语言层面引入了对多线程并发编程的支持,标志着 C++ 正式迈入现代并发编程时代。它不仅定义了一个新的内存模型(memory model),还提供了标准库中的多线程工具,如:
- std::thread
- :用于创建和管理线程。
- std::mutex
- :互斥锁,用于保护共享资源。
- std::condition_variable
- :条件变量,用于线程间通信。
- std::atomic
- :原子操作,用于无锁编程。
这些特性使得开发者可以在不依赖平台相关 API 的前提下,编写可移植、安全且高效的并发程序。
示例代码:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx; // 互斥锁
std::condition_variable cv; // 条件变量
bool ready = false; // 共享状态标志
// 线程函数:等待“就绪”信号
void print_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
while (!ready) {
cv.wait(lock); // 阻塞等待通知
}
// 当 ready == true 时继续执行
std::cout << "Thread " << id << '\n';
}
// 主线程调用此函数,触发所有线程继续执行
void go() {
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cv.notify_all(); // 唤醒所有等待的线程
}
int main() {
const int thread_count = 10;
std::thread threads[thread_count];
// 创建并启动多个线程
for (int i = 0; i < thread_count; ++i) {
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race...\n";
go(); // 触发所有线程开始执行
// 等待所有线程完成
for (auto& th : threads) {
th.join();
}
return 0;
}- 使用 std::thread 时,务必调用 join() 或 detach(),否则程序会在主线程结束时终止未完成的子线程,导致未定义行为。
- 多线程环境下,任何共享数据都应使用互斥量进行保护,避免数据竞争。
8. 右值引用(Rvalue Reference)
C++11 引入了 右值引用(Rvalue Reference),使用 && 声明,专门用于绑定到临时对象(右值),从而实现对资源的高效转移。
右值引用是现代 C++ 实现移动语义(Move Semantics)和完美转发(Perfect Forwarding)的基础,极大地提升了程序性能并增强了泛型编程能力。
示例代码:
#include <iostream>
int main() {
int x = 10; // x 是左值
int&& rref = 20; // 20 是右值,rref 是右值引用
std::cout << "右值引用的值: " << rref << std::endl;
return 0;
}在这个例子中:
- x 是一个具名变量,是一个左值。
- 20 是一个字面量,属于右值。
- rref 是一个右值引用,绑定到了这个临时值上。
右值引用的核心作用
(1). 移动语义(Move Semantics)
传统的拷贝构造函数和赋值运算符会进行深拷贝,对于包含动态资源(如堆内存、文件句柄等)的大对象来说,代价高昂。
而 C++11 引入的 移动构造函数 和 移动赋值运算符 利用右值引用,允许我们直接“偷走”临时对象的资源,而不是复制它。
示例:自定义类实现移动构造函数
#include <iostream>
#include <vector>
class MyVector {
public:
std::vector<int>* data;
// 构造函数
MyVector() : data(new std::vector<int>({1, 2, 3})) {
std::cout << "构造\n";
}
// 拷贝构造函数(深拷贝)
MyVector(const MyVector& other) : data(new std::vector<int>(*other.data)) {
std::cout << "拷贝构造\n";
}
// 移动构造函数(资源转移)
MyVector(MyVector&& other) noexcept : data(other.data) {
other.data = nullptr; // 把原对象置空,防止多次释放
std::cout << "移动构造\n";
}
// 析构函数
~MyVector() {
if (data) delete data;
std::cout << "析构\n";
}
};
MyVector createTemp() {
MyVector v;
return v; // 返回临时对象,将调用移动构造函数
}
int main() {
MyVector a = createTemp(); // 这里将调用移动构造函数(而非拷贝构造)
return 0;
}可以看到,返回临时对象时并没有发生深拷贝,而是通过移动语义完成了资源的转移。
(2). 完美转发(Perfect Forwarding)
右值引用结合模板类型推导和 std::forward,可以实现完美转发,即在函数模板中将参数以原始值类别(左值/右值)传递给另一个函数。
这在编写通用库函数(如 std::make_shared、std::vector::emplace_back 等)时非常有用。
示例:完美转发
#include <iostream>
#include <utility> // std::forward
template<typename T>
void wrapper(T&& arg) {
call(std::forward<T>(arg)); // 将 arg 原样转发给 call()
}这样无论传入的是左值还是右值,都能保持其原始特性,避免不必要的拷贝或错误的行为。
9.正则表达式
正则表达式是一种强大的文本处理工具,它通过特定的语法规则构建匹配模式,主要用于实现以下核心功能:
1.模式验证:检测字符串中是否存在符合特定规则的子串
2.文本替换:查找并替换符合模式的字符串片段
3.数据提取:从文本中捕获符合特定格式的内容片段
以下是 C++11 中正则表达式库的一些关键组件:
- regex 类:表示一个正则表达式。你可以用它来编译一个正则表达式字符串,并之后用这个编译后的正则表达式进行匹配操作。
- regex_match 函数:用于确定一个整个字符串是否与一个正则表达式匹配。
- regex_search 函数:用于在一个字符串中搜索与正则表达式匹配的子串。
- regex_replace 函数:用于在字符串中替换与正则表达式匹配的子串。
- smatch 类:是一个特化的模板类,用于存储 regex_search 和 regex_match 的结果。它是一个 std::match_results<std::string::const_iterator> 的类型定义。
- regex_constants 命名空间:包含了一些用于指定正则表达式语法和匹配行为的标志。
示例代码:
#include <iostream>
#include <string>
#include <regex>
int main() {
std::string s("Example string for regex matching.");
std::regex e("regex"); // 正则表达式字面量
// 使用 regex_search 查找匹配的子串
if (std::regex_search(s, e)) {
std::cout << "String contains 'regex'.\n";
} else {
std::cout << "String does not contain 'regex'.\n";
}
// 使用 regex_replace 替换匹配的子串
std::string replaced = std::regex_replace(s, e, "pattern");
std::cout << "Replaced string: " << replaced << std::endl;
// 使用 smatch 存储匹配结果
std::smatch match;
if (std::regex_search(s, match, e)) {
std::cout << "Match found: " << match.str() << std::endl;
}
return 0;
}C++11的新特性还包括static_assert、override/final、constexpr等,这些特性共同提升了C++语言的表达能力和开发效率。
相关推荐
- win10自带文件恢复工具(win10文件恢复工具推荐)
-
步骤:第一步:打开系统的管理员命令提示符窗口。Windows10系统打开管理员命令提示符窗口有如下几种方法:方法一:在系统桌面左下角的搜索栏输入:CMD,点击:命令提示符,可以打开管理员命令提示符窗口...
- 电脑本地磁盘c盘满了怎么办(电脑本地磁盘c盘满了如何删除)
-
当您的电脑本地磁盘C满了时,可能会出现一些问题,例如无法安装新程序、无法保存文件等。以下是一些解决方法:1.删除不需要的文件:可以通过手动删除不需要的文件或使用磁盘清理工具来清理本地磁盘C。在清理磁...
- 傲游浏览器(傲游浏览器app下载)
-
1、开始——程序——找到遨游——打开,如果能打开说明快捷方式有问题2、362急救箱系统修复、网络修复傲游浏览器曾经是一个备受推荐的浏览器,由于其强大的功能和用户友好的界面,在中国的浏览器市场占有一...
- 电脑怎么定时关机软件(电脑怎样定时开关机软件)
-
给电脑设置定时开关机的方法如下:1、点击桌面左下角的开始按钮,打开“控制面板”。2、然后我们点击“系统和安全3、点击下方的“管理工具”。4、再点击“任务计划程序”。5、点击“计划任务程序库”,选择“创...
- 网易邮箱企业邮箱登录入口(网易邮箱企业免费邮箱登录)
-
网易企业邮箱官网(qiye.163.com),除此之外所看到的都是经销商网站。现阶段在该官网是可以填写信息直接开通网易企业邮箱体验试用的。如果有不明白的地方需要专人服务也是可以在官网点击在线咨询按钮或...
-
- qq电子邮箱怎么写(电子邮件信箱怎么注册)
-
1.每个人在注册QQ时都会有关联的一个邮箱,它的格式就是“QQ号码@qq.com”。2.用户可以免费开通自己的手机号码邮箱帐号。3.QQ邮箱还可以注册“……@foxmail.com”这样的商务型帐号。4.@qq.com邮箱可以有...
-
2026-01-12 22:05 liuian
- 台式机装机步骤(台式机 装机)
-
原因:1、更新的驱动不正确或未更新完成(使用USB键鼠经常发生);2、电脑更新驱动时假死,导致进程反应过慢。解决方法:1、如更新时驱动不正确,USB键盘、鼠标无作用时;可等待1~2分钟,看键鼠是否恢复...
- win8手机下载安装(win8安卓)
-
在电脑上面就可以下载,打开浏览器搜索windous8系统会出现一些下拉选择,选择第一条或者选择有官网字样的,就直接有下载按钮,然后点击下载就可以了关闭应用自动更新第一步、在系统中找到应用商店。第二...
- 台式电脑显卡怎么升级(台式电脑显卡升级方案)
-
一般情况下,建议到产品(您的显卡)品牌官网上去下载相应最新的驱动,这虽然并不能保证一定就是显卡最新的驱动,但相对于稳定性来说是首选。如果是高级玩家,追求更新、更好的性能发挥,可以利用驱动精灵一类的驱动...
- u盘数据丢失的原因(u盘数据丢失的原因有哪些)
-
U盘出现了损坏造成的磁道出现了损坏。这个U盘的磁道是最容易损坏的,有的时候你不知道怎么碰到它,它就有数据丢失了就无法显示这样的情况,你可以在电脑上进行修复,首先你点击U盘右键找到属性选择修复,这样把...
- window7下载哪个版本的ie(windows7用哪个版本的ie浏览器)
-
WIN7系统自带的IE浏览器是8.0版本的。IE全称InternetExplorer,是美国微软公司推出的一款网页浏览器。IE8扩展的新功能有:1、Activities(活动内容服务)。用户可以从网页...
- 服务器回收(上海服务器回收)
-
回收服务器内存后,首先应该彻底清除内存存储的所有数据和敏感信息,然后进行分类处理。如果内存仍然有效,可以进行检测、测试和修复后再重新使用。如果内存已损坏或过期,应该妥善处理,比如通过专业的硬件回收公司...
- 戴尔官网入口学生通道(戴尔学生渠道)
-
戴尔官网地址如下,在浏览器输入就可以加入了。DELL官方网站http://www.dell.com.cn/DELL官方旗舰店(天猫)http://dell.tmall.com/DELL官方旗舰店(京东...
- win7旗舰版激活码病毒(win7旗舰版激活密钥 永久激活码)
-
激活和破解工具会修改一些系统文件或数据,一般都会被杀毒软件识别为木马。而且现在网上的windows和office激活工具有的确实是带有木马的,最好去值得信任的网站或者论坛下载。
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
