C++11中的右值引用和完美转发
C++11中的右值引用和完美转发
右值引用
右值引用是 C++11 引入的一种新的引用类型,用 && 表示。它主要用于区分左值和右值,并且可以实现移动语义,避免不必要的深拷贝,提高程序的性能。左值通常是可以取地址的表达式,而右值是临时对象或字面量,不能取地址。
示例代码:
#include <iostream>
#include <vector>class MyClass {
public:// 构造函数MyClass() : data(new int[1000]) {std::cout << "Default constructor" << std::endl;}// 拷贝构造函数MyClass(const MyClass& other) : data(new int[1000]) {for (int i = 0; i < 1000; ++i) {data[i] = other.data[i];}std::cout << "Copy constructor" << std::endl;}// 移动构造函数MyClass(MyClass&& other) noexcept : data(other.data) {other.data = nullptr;std::cout << "Move constructor" << std::endl;}// 析构函数~MyClass() {delete[] data;}private:int* data;
};int main() {MyClass obj1; // 调用默认构造函数MyClass obj2(obj1); // 调用拷贝构造函数// 创建一个临时对象(右值)MyClass obj3(MyClass()); // 调用移动构造函数std::vector<MyClass> vec;vec.push_back(MyClass()); // 调用移动构造函数return 0;
}
代码解释:
- 默认构造函数:用于创建对象时分配内存。
拷贝构造函数:当使用一个已存在的对象初始化另一个对象时调用,需要进行深拷贝,将原对象的数据复制到新对象中。 - 移动构造函数:接受一个右值引用作为参数,将原对象的资源(如指针)直接转移到新对象中,避免了深拷贝,提高了性能。
- 在 main 函数中,obj1 调用默认构造函数创建,obj2 调用拷贝构造函数从 obj1 复制而来,obj3 和 vec.push_back(MyClass()) 中的临时对象都是右值,会调用移动构造函数。
完美转发
完美转发是指在函数模板中,将参数以原始的左值或右值属性传递给其他函数,避免不必要的拷贝和移动操作。std::forward 是 C++ 标准库中用于实现完美转发的工具,定义在 头文件中。
示例代码:
#include <iostream>
#include <utility>// 目标函数,接受左值引用
void process(int& value) {std::cout << "Processing lvalue: " << value << std::endl;
}// 目标函数,接受右值引用
void process(int&& value) {std::cout << "Processing rvalue: " << value << std::endl;
}// 转发函数模板
template<typename T>
void forwarder(T&& arg) {process(std::forward<T>(arg));
}int main() {int x = 10;forwarder(x); // 传递左值forwarder(20); // 传递右值return 0;
}
示例代码:
#include <iostream>
#include <utility>// 目标函数,接受左值引用
void process(int& value) {std::cout << "Processing lvalue: " << value << std::endl;
}// 目标函数,接受右值引用
void process(int&& value) {std::cout << "Processing rvalue: " << value << std::endl;
}// 转发函数模板
template<typename T>
void forwarder(T&& arg) {process(std::forward<T>(arg));
}int main() {int x = 10;forwarder(x); // 传递左值forwarder(20); // 传递右值return 0;
}
代码解释:
- process 函数:有两个重载版本,分别接受左值引用和右值引用,用于处理不同类型的参数。
- forwarder 函数模板:使用万能引用 T&& 接受参数,然后使用 std::forward(arg) 将参数以原始的左值或右值属性转发给 process 函数。
- 在 main 函数中,forwarder(x) 传递的是左值,会调用 process(int&) 版本;forwarder(20) 传递的是右值,会调用 process(int&&) 版本。通过 std::forward 实现了参数的完美转发。
右值引用和完美转发常见的使用场景
右值引用和完美转发是 C++11 引入的重要特性,在实际应用中有许多常见的使用场景,下面为你详细介绍:
右值引用的常见使用场景
1. 移动构造函数和移动赋值运算符
移动语义是右值引用最主要的应用场景之一,通过移动构造函数和移动赋值运算符,可以避免不必要的深拷贝,提高程序的性能。
示例代码:
#include <iostream>
#include <string>class MyString {
private:char* data;size_t length;public:// 构造函数MyString(const char* str = "") {length = strlen(str);data = new char[length + 1];strcpy(data, str);}// 拷贝构造函数MyString(const MyString& other) {length = other.length;data = new char[length + 1];strcpy(data, other.data);}// 移动构造函数MyString(MyString&& other) noexcept {length = other.length;data = other.data;other.data = nullptr;other.length = 0;}// 析构函数~MyString() {delete[] data;}
};int main() {MyString str1("Hello");MyString str2(std::move(str1)); // 调用移动构造函数return 0;
}
解释:在上述代码中,当使用 std::move 将 str1 转换为右值后,调用了移动构造函数,直接将 str1 的资源(指针)转移到 str2 中,避免了深拷贝,提高了性能。
2. 标准库容器的插入操作
标准库容器(如 std::vector、std::list 等)在插入临时对象时,会优先调用移动构造函数,避免不必要的拷贝。
示例代码:
#include <iostream>
#include <vector>
#include <string>int main() {std::vector<std::string> vec;vec.push_back(std::string("Hello")); // 调用移动构造函数return 0;
}
解释:std::string(“Hello”) 是一个临时对象(右值),vec.push_back 会优先调用 std::string 的移动构造函数,将临时对象的资源转移到容器内部,避免了深拷贝。
3. 智能指针的移动语义
智能指针(如 std::unique_ptr、std::shared_ptr)利用右值引用实现了移动语义,确保资源的所有权可以安全地转移。
示例代码:
#include <iostream>
#include <memory>int main() {std::unique_ptr<int> ptr1 = std::make_unique<int>(10);std::unique_ptr<int> ptr2 = std::move(ptr1); // 转移所有权return 0;
}
解释:std::unique_ptr 不允许拷贝,因为它是独占资源的。通过 std::move 将 ptr1 转换为右值后,调用了移动构造函数,将资源的所有权从 ptr1 转移到 ptr2 中。
完美转发的常见使用场景
1. 函数包装器和转发函数
在实现函数包装器或转发函数时,完美转发可以确保参数以原始的左值或右值属性传递给被包装的函数。
示例代码:
#include <iostream>
#include <utility>// 目标函数
void print(int& value) {std::cout << "Lvalue: " << value << std::endl;
}void print(int&& value) {std::cout << "Rvalue: " << value << std::endl;
}// 转发函数模板
template<typename T>
void forwarder(T&& arg) {print(std::forward<T>(arg));
}int main() {int x = 10;forwarder(x); // 传递左值forwarder(20); // 传递右值return 0;
}
解释:forwarder 函数模板使用万能引用 T&& 接受参数,然后使用 std::forward 将参数以原始的左值或右值属性转发给 print 函数,确保 print 函数能够正确处理不同类型的参数。
2. 工厂函数
在工厂函数中,完美转发可以确保传递给构造函数的参数以原始的左值或右值属性传递,避免不必要的拷贝。
示例代码:
#include <iostream>
#include <memory>
#include <utility>class MyClass {
public:MyClass(int value) : data(value) {std::cout << "Constructed with value: " << data << std::endl;}
private:int data;
};// 工厂函数
template<typename... Args>
std::unique_ptr<MyClass> createMyClass(Args&&... args) {return std::make_unique<MyClass>(std::forward<Args>(args)...);
}int main() {int x = 10;auto obj1 = createMyClass(x); // 传递左值auto obj2 = createMyClass(20); // 传递右值return 0;
}
解释:createMyClass 是一个工厂函数,使用完美转发将参数传递给 MyClass 的构造函数,确保构造函数能够正确处理不同类型的参数,避免不必要的拷贝。
3. 实现可变参数模板类和函数
在实现可变参数模板类和函数时,完美转发可以确保每个参数都以原始的左值或右值属性传递。
示例代码:
#include <iostream>
#include <utility>// 可变参数模板函数
template<typename... Args>
void callFunction(Args&&... args) {// 这里可以调用其他函数并传递参数// 示例:调用 print 函数auto printArgs = [](auto&& arg) {std::cout << arg << " ";};(printArgs(std::forward<Args>(args)), ...);std::cout << std::endl;
}int main() {int x = 10;callFunction(x, 20, "Hello");return 0;
}
解释:callFunction 是一个可变参数模板函数,使用完美转发将每个参数以原始的左值或右值属性传递给 printArgs 函数,确保参数的类型信息不丢失。
完美转发在多线程编程中的应用
在多线程编程中,完美转发有着重要的应用,它可以帮助我们更高效、更安全地在不同线程间传递参数,避免不必要的拷贝,下面详细介绍其常见应用场景:
1. 线程创建时传递参数
在使用 std::thread 创建线程时,需要将参数传递给线程函数。使用完美转发可以确保参数以原始的左值或右值属性传递给线程函数,避免不必要的拷贝操作,提高性能。
示例代码:
#include <iostream>
#include <thread>
#include <utility>// 线程函数
void threadFunction(int& value) {std::cout << "Processing lvalue: " << value << std::endl;
}void threadFunction(int&& value) {std::cout << "Processing rvalue: " << value << std::endl;
}// 转发函数模板
template<typename Func, typename... Args>
void createThread(Func&& func, Args&&... args) {std::thread t(std::forward<Func>(func), std::forward<Args>(args)...);t.join();
}int main() {int x = 10;// 传递左值createThread(threadFunction, x);// 传递右值createThread(threadFunction, 20);return 0;
}
代码解释:
- createThread 是一个模板函数,使用完美转发将函数 func 和参数 args 传递给 std::thread 的构造函数。
- 在 main 函数中,分别传递左值 x 和右值 20 给 createThread 函数,确保线程函数能够正确处理不同类型的参数。
2. 任务队列中传递任务和参数
在多线程编程中,任务队列是一种常见的设计模式,用于将任务和参数封装并传递给工作线程。完美转发可以确保任务和参数以原始的左值或右值属性添加到任务队列中,避免不必要的拷贝。
示例代码:
#include <iostream>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <utility>// 任务队列类
class TaskQueue {
public:// 向任务队列中添加任务template<typename Func, typename... Args>void enqueue(Func&& func, Args&&... args) {{std::unique_lock<std::mutex> lock(mtx_);// 使用完美转发将任务和参数包装成可调用对象并添加到队列中tasks_.emplace([func = std::forward<Func>(func), args = std::make_tuple(std::forward<Args>(args)...)]() {std::apply(func, args);});}// 通知等待的线程有新任务加入cv_.notify_one();}// 从任务队列中取出并执行任务void dequeue() {std::function<void()> task;{std::unique_lock<std::mutex> lock(mtx_);// 等待队列中有任务cv_.wait(lock, [this] { return!tasks_.empty(); });// 取出队列中的第一个任务task = std::move(tasks_.front());tasks_.pop();}// 执行任务task();}private:std::queue<std::function<void()>> tasks_; // 任务队列std::mutex mtx_; // 互斥锁,用于保护任务队列std::condition_variable cv_; // 条件变量,用于线程同步
};// 示例任务函数
void taskFunction(int value) {std::cout << "Executing task with value: " << value << std::endl;
}int main() {TaskQueue taskQueue;// 创建一个工作线程std::thread worker([&taskQueue] {while (true) {taskQueue.dequeue();}});// 向任务队列中添加任务for (int i = 0; i < 5; ++i) {taskQueue.enqueue(taskFunction, i);}// 等待一段时间,确保任务执行完成std::this_thread::sleep_for(std::chrono::seconds(1));// 终止工作线程worker.detach();return 0;
}
代码解释:
- TaskQueue 类的 enqueue 方法使用完美转发将任务函数 func 和参数 args 包装成一个可调用对象,并添加到任务队列中。
- std::apply 用于调用包装的任务函数,并传递参数。
- 在 main 函数中,向任务队列中添加任务,工作线程从队列中取出任务并执行。
3. 异步操作中传递参数
在异步编程中,例如使用 std::async 启动异步任务时,完美转发可以确保参数以原始的左值或右值属性传递给异步任务函数。
示例代码:
#include <iostream>
#include <future>
#include <utility>// 异步任务函数
int asyncFunction(int value) {std::cout << "Processing value: " << value << std::endl;return value * 2;
}// 转发函数模板
template<typename Func, typename... Args>
auto asyncForward(Func&& func, Args&&... args) {return std::async(std::launch::async, std::forward<Func>(func), std::forward<Args>(args)...);
}int main() {int x = 10;// 传递左值auto future1 = asyncForward(asyncFunction, x);// 传递右值auto future2 = asyncForward(asyncFunction, 20);std::cout << "Result 1: " << future1.get() << std::endl;std::cout << "Result 2: " << future2.get() << std::endl;return 0;
}
代码解释:
- asyncForward 是一个模板函数,使用完美转发将函数 func 和参数 args 传递给 std::async 函数。
- 在 main 函数中,分别传递左值 x 和右值 20 给 asyncForward 函数,启动异步任务并获取结果。
除了线程创建,完美转发在多线程编程的许多其他场景中也有重要应用,以下是一些常见的场景:
1. 任务池与任务调度
在任务池系统中,需要将不同类型的任务及其参数封装并调度到各个工作线程执行。完美转发可以确保任务和参数在传递过程中保持原始的左值或右值属性,避免不必要的拷贝。
#include <iostream>
#include <queue>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <vector>
#include <utility>class TaskPool {
public:TaskPool(size_t numThreads) {for (size_t i = 0; i < numThreads; ++i) {threads.emplace_back([this] {while (true) {std::function<void()> task;{std::unique_lock<std::mutex> lock(mutex_);cv_.wait(lock, [this] { return!tasks.empty() || stop; });if (stop && tasks.empty()) return;task = std::move(tasks.front());tasks.pop();}task();}});}}~TaskPool() {{std::unique_lock<std::mutex> lock(mutex_);stop = true;}cv_.notify_all();for (std::thread& thread : threads) {thread.join();}}template<typename Func, typename... Args>void enqueue(Func&& func, Args&&... args) {{std::unique_lock<std::mutex> lock(mutex_);tasks.emplace([func = std::forward<Func>(func), args = std::make_tuple(std::forward<Args>(args)...) ]() {std::apply(func, args);});}cv_.notify_one();}private:std::queue<std::function<void()>> tasks;std::vector<std::thread> threads;std::mutex mutex_;std::condition_variable cv_;bool stop = false;
};// 示例任务函数
void printMessage(const std::string& message) {std::cout << "Task: " << message << std::endl;
}int main() {TaskPool pool(2);pool.enqueue(printMessage, "Hello from task 1");pool.enqueue(printMessage, "Hello from task 2");return 0;
}
解释:
- TaskPool 类实现了一个简单的任务池,包含多个工作线程。
- enqueue 方法使用完美转发将任务函数和参数封装成一个可调用对象,并添加到任务队列中。
- 通过 std::apply 调用封装的任务函数并传递参数,确保参数的原始属性被保留。
2. 消息传递系统
在多线程的消息传递系统中,线程之间需要交换各种类型的消息。完美转发可以高效地传递消息对象,避免消息对象的不必要拷贝。
#include <iostream>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <utility>template<typename Message>
class MessageQueue {
public:template<typename Msg>void send(Msg&& msg) {{std::unique_lock<std::mutex> lock(mutex_);queue_.emplace(std::forward<Msg>(msg));}cv_.notify_one();}Message receive() {std::unique_lock<std::mutex> lock(mutex_);cv_.wait(lock, [this] { return!queue_.empty(); });Message msg = std::move(queue_.front());queue_.pop();return msg;}private:std::queue<Message> queue_;std::mutex mutex_;std::condition_variable cv_;
};// 示例消息类
class MyMessage {
public:MyMessage(int data) : data_(data) {}int getData() const { return data_; }
private:int data_;
};void sender(MessageQueue<MyMessage>& queue) {queue.send(MyMessage(42));
}void receiver(MessageQueue<MyMessage>& queue) {MyMessage msg = queue.receive();std::cout << "Received message with data: " << msg.getData() << std::endl;
}int main() {MessageQueue<MyMessage> queue;std::thread senderThread(sender, std::ref(queue));std::thread receiverThread(receiver, std::ref(queue));senderThread.join();receiverThread.join();return 0;
}
解释:
- MessageQueue 类实现了一个简单的消息队列,用于线程间的消息传递。
- send 方法使用完美转发将消息对象添加到队列中,确保消息对象以原始的左值或右值属性入队。
- receive 方法从队列中取出消息对象并返回。
3. 异步回调机制
在异步编程中,经常会使用回调函数来处理异步操作的结果。完美转发可以确保回调函数的参数以原始的左值或右值属性传递。
#include <iostream>
#include <functional>
#include <thread>
#include <utility>template<typename Callback, typename... Args>
void asyncOperation(Callback&& callback, Args&&... args) {std::thread([callback = std::forward<Callback>(callback), args = std::make_tuple(std::forward<Args>(args)...) ]() {// 模拟异步操作std::this_thread::sleep_for(std::chrono::seconds(1));std::apply(callback, args);}).detach();
}void callbackFunction(int value) {std::cout << "Callback received value: " << value << std::endl;
}int main() {asyncOperation(callbackFunction, 42);std::this_thread::sleep_for(std::chrono::seconds(2));return 0;
}
解释:
- asyncOperation 函数模拟一个异步操作,在新线程中执行。
- 使用完美转发将回调函数和参数封装在一个 lambda 表达式中,并在异步操作完成后调用回调函数。
- std::apply 用于调用回调函数并传递参数,确保参数的原始属性被保留。
在多线程编程中,右值引用和完美转发哪个更常用?
在多线程编程中,完美转发(Perfect Forwarding) 比右值引用(Rvalue Reference)更常用。虽然右值引用是实现完美转发的基础,但完美转发作为一种更高层次的抽象,直接解决了多线程场景中参数传递的核心问题 ——高效保留参数的原始值属性(左值或右值),从而避免不必要的拷贝或移动操作。
为什么完美转发更常用?
1. 多线程参数传递的核心需求
多线程编程中,经常需要将任务函数及其参数封装后传递给其他线程(如任务池、消息队列)。此时,完美转发可以确保:
- 左值参数以左值形式传递(避免不必要的移动)。
- 右值参数以右值形式传递(允许高效移动)。
例如,在任务池的 enqueue 方法中:
template<typename Func, typename... Args>
void enqueue(Func&& func, Args&&... args) {tasks.emplace([func = std::forward<Func>(func), args = std::make_tuple(std::forward<Args>(args)...) ]() {std::apply(func, args);});
}
这里的 std::forward 确保 func 和 args 的原始值属性被保留,避免额外拷贝。
2. 封装与通用性
完美转发通常与模板结合使用,能够处理任意类型的参数,极大提升代码的通用性。例如:
- 消息队列的 send 方法:
template<typename Msg>
void send(Msg&& msg) {queue_.emplace(std::forward<Msg>(msg));
}
- 异步回调的 asyncOperation 函数:
template<typename Callback, typename... Args>
void asyncOperation(Callback&& callback, Args&&... args) {// 完美转发参数到线程中
}
3. 减少手动干预
右值引用需要显式使用 && 语法,而完美转发通过模板和 std::forward 自动推断值类别,减少了程序员的手动干预。例如:
// 手动使用右值引用(需显式区分)
void process(RvalueType&& value);// 完美转发(自动处理)
template<typename T>
void process(T&& value) {doSomething(std::forward<T>(value));
}
右值引用的作用
右值引用是完美转发的基础,但通常作为底层机制存在,而非直接使用。它的核心作用是:
- 支持移动语义:允许对象资源高效转移(如 std::vector 的 push_back)。
- 实现完美转发:通过 T&& 模板参数捕获任意值类型。
总结
| 特性 | 多线程中的使用场景 | 常用程度 |
|---|---|---|
| 完美转发 | 任务封装、消息传递、异步回调等参数传递场景 | 更常用 |
| 右值引用 | 实现移动语义或作为完美转发的底层支持 | 较少直接使用 |
结论:在多线程编程中,完美转发是更常用的工具,因为它直接解决了参数传递的效率问题,而右值引用更多作为其实现的基础设施存在。
相关文章:
C++11中的右值引用和完美转发
C11中的右值引用和完美转发 右值引用 右值引用是 C11 引入的一种新的引用类型,用 && 表示。它主要用于区分左值和右值,并且可以实现移动语义,避免不必要的深拷贝,提高程序的性能。左值通常是可以取地址的表达式…...
Redis详解(实战 + 面试)
目录 Redis 是单线程的!为什么 Redis-Key(操作redis的key命令) String 扩展字符串操作命令 数字增长命令 字符串范围range命令 设置过期时间命令 批量设置值 string设置对象,但最好使用hash来存储对象 组合命令getset,先get然后在set Hash hash命令: h…...
ISP CIE-XYZ色彩空间
1. 颜色匹配实验 1931年,CIE综合了前人实验数据,统一采用700nm(红)、546.1nm(绿)、435.8nm(蓝)作为标准三原色波长,绘制了色彩匹配函数,如下图。选定这些波…...
【强化学习笔记1】从强化学习的基本概念到近端策略优化(PPO)
好久没有更新了。最近想学习一下强化学习,本系列是李宏毅老师强化学习的课程笔记。 1. Policy-based Model 1.1 Actor 在policy-based model中,主要的目的就是训练一个actor。 对于一个episode(例如,玩一局游戏)&…...
Deepseek对ChatGPT的冲击?
从测试工程师的视角来看,DeepSeek对ChatGPT的冲击主要体现在**测试场景的垂直化需求与通用模型局限性之间的博弈**。以下从技术适配性、效率优化、风险控制及未来趋势四个维度展开分析: --- ### **一、技术适配性:垂直领域能力决定工具选择…...
STM32中的ADC
目录 一:什么是ADC 二:ADC的用途 三:STM32F103ZET6的ADC 3.1ADC对应的引脚 3.2ADC时钟 3.3ADC的工作模式 编辑3.4ADC校准 3.5ADC转换结构和实际电压的换算 四:ADC配置步骤 五:两个重要的函数 一:…...
开启AI短剧新纪元!SkyReels-V1/A1双剑合璧!昆仑万维开源首个面向AI短剧的视频生成模型
论文链接:https://arxiv.org/abs/2502.10841 项目链接:https://skyworkai.github.io/skyreels-a1.github.io/ Demo链接:https://www.skyreels.ai/ 开源地址:https://github.com/SkyworkAI/SkyReels-A1 https://github.com/Skywork…...
【uniapp】在UniApp中实现持久化存储:安卓--生成写入数据为jsontxt
在移动应用开发中,数据存储是一个至关重要的环节。对于使用UniApp开发的Android应用来说,缓存(Cache)是一种常见的数据存储方式,它能够提高应用的性能和用户体验。然而,缓存数据在用户清除缓存或清除应用数…...
大白话React第十一章React 相关的高级特性以及在实际项目中的应用优化
假设我们已经对 React 前端框架的性能和可扩展性评估有了一定了解,接下来的阶段可以深入学习 React 相关的高级特性以及在实际项目中的应用优化,以下是详细介绍及代码示例: 1. React 高级特性的深入学习 1.1 React 并发模式(Con…...
java容器 LIst、set、Map
Java容器中的List、Set、Map是核心数据结构,各自适用于不同的场景 一、List(有序、可重复) List接口代表有序集合,允许元素重复和通过索引访问,主要实现类包括: ArrayList 底层结构:动态数组…...
使用IDEA如何隐藏文件或文件夹
选择file -> settings 选择Editor -> File Types ->Ignored Files and Folders (忽略文件和目录) 点击号就可以指定想要隐藏的文件或文件夹...
DOM HTML:深入理解与高效运用
DOM HTML:深入理解与高效运用 引言 随着互联网的飞速发展,前端技术逐渐成为软件开发中的关键部分。DOM(文档对象模型)和HTML(超文本标记语言)是前端开发中的基石。本文将深入探讨DOM和HTML的概念、特性以及在实际开发中的应用,帮助读者更好地理解和使用这两项技术。 …...
形象生动讲解Linux 虚拟化 I/O
用现实生活的比喻和简单例子来解释 Linux 虚拟化 I/O,就像给朋友讲故事一样。 虚拟化 I/O 要解决什么问题? 想象你有一栋大房子(物理服务器),想把它分割成多个小公寓(虚拟机)出租。每个租客&…...
git从零学起
从事了多年java开发,一直在用svn进行版本控制,如今更换了公司,使用的是git进行版本控制,所以打算记录一下git学习的点滴,和大家一起分享。 百度百科: Git(读音为/gɪt/)是一个开源…...
汽车低频发射天线介绍
汽车低频PKE天线是基于RFID技术的深度研究及产品开发应用的一种天线,在汽车的智能系统中发挥着重要作用,以下是关于它的详细介绍: 移动管家PKE低频天线结构与原理 结构:产品一般由一个高Q值磁棒天线和一个高压电容组成ÿ…...
【Java分布式】Nacos注册中心
Nacos注册中心 SpringCloudAlibaba 也推出了一个名为 Nacos 的注册中心,相比 Eureka 功能更加丰富,在国内受欢迎程度较高。 官网:https://nacos.io/zh-cn/ 集群 Nacos就将同一机房内的实例划分为一个集群,一个服务可以包含多个集…...
【C++】ImGui:极简化的立即模式GUI开发
如果你是GUI开发的新手,或想试试轻量级、易集成的GUI库,ImGui(即时模式图形用户界面)是个不错的选择。它以简洁的API、跨平台的兼容性和卓越的性能,受到许多开发者的喜爱。无论是为C项目添加调试界面,还是构…...
5G学习笔记之BWP
我们只会经历一种人生,我们选择的人生。 参考:《5G NR标准》、《5G无线系统指南:如微见著,赋能数字化时代》 目录 1. 概述2. BWP频域位置3. 初始与专用BWP4. 默认BWP5. 切换BWP 1. 概述 在LTE的设计中,默认所有终端均能处理最大2…...
1. 搭建前端+后端开发框架
1. 说明 本篇博客主要介绍网页开发中,搭建前端和后端开发框架的具体步骤,框架中所使用的技术栈如下: 前端:VUE Javascript 后端:Python Flask Mysql 其中MySQL主要用来存储需要的数据,在本文中搭建基本…...
深入浅出:插入排序算法完全解析
1. 什么是插入排序? 插入排序(Insertion Sort)是一种简单的排序算法,其基本思想与我们整理扑克牌的方式非常相似。我们将扑克牌从第二张开始依次与前面已排序的牌进行比较,将其插入到合适的位置,直到所有牌…...
(十一)基于vue3+mapbox-GL实现模拟高德实时导航轨迹播放
要在 Vue 3 项目中结合 Mapbox GL 实现类似高德地图的实时导航轨迹功能,您可以按照以下步骤进行: 安装依赖: 首先,安装 mapbox-gl 和 @turf/turf 这两个必要的库: npm install mapbox-gl @turf/turf引入 Mapbox GL: 在组件中引入 mapbox-gl 并初始化地图实例: <templ…...
DeepSeek到TinyLSTM的知识蒸馏
一、架构设计与适配 模型结构对比: DeepSeek(教师模型):基于Transformer,多头自注意力机制,层数≥12,隐藏层维度≥768TinyLSTM(学生模型):单层双向LSTM&#…...
【Transformer模型学习】第三篇:位置编码
文章目录 0. 前言1. 为什么需要位置编码?2. 如何进行位置编码?3. 正弦和余弦位置编码4. 举个例子4.1 参数设置4.2 计算分母项4.3 计算位置编码4.4 位置编码矩阵 5. 相对位置信息6. 改进的位置编码方式——RoPE6.1 RoPE的核心思想6.2 RoPE的优势 7. 总结 …...
微信小程序自定义导航栏实现指南
文章目录 微信小程序自定义导航栏实现指南一、自定义导航栏的需求分析二、代码实现1. WXML 结构2. WXSS 样式样式解析:3. JavaScript 逻辑三、完整代码示例四、注意事项与优化建议五、总结微信小程序自定义导航栏实现指南 在微信小程序开发中,默认的导航栏样式可能无法满足所…...
(十 六)趣学设计模式 之 责任链模式!
目录 一、 啥是责任链模式?二、 为什么要用责任链模式?三、 责任链模式的实现方式四、 责任链模式的优缺点五、 责任链模式的应用场景六、 总结 🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,…...
20250225-代码笔记03-class CVRPModel AND other class
文章目录 前言一、class CVRPModel(nn.Module):__init__(self, **model_params)函数功能函数代码 二、class CVRPModel(nn.Module):pre_forward(self, reset_state)函数功能函数代码 三、class CVRPModel(nn.Module):forward(self, state)函数功能函数代码 四、def _get_encodi…...
面试常问的压力测试问题
性能测试作为软件开发中的关键环节,确保系统在高负载下仍能高效运行。压力测试作为性能测试的重要类型,旨在通过施加超出正常负载的压力,观察系统在极端条件下的表现。面试中,相关问题常被问及,包括定义、重要性、与负…...
Python——365天学习规划
文章目录 1. 第一阶段:Python基础(Day 1-60) 1.1 Week 1-2:基础语法 1.1.1 Day 1-3:变量、数据类型、运算符、输入输出 1.1.2 Day 4-7:条件语句(if-elif-else) 1.1.3 Day 8-14&…...
河南理工XCPC萌新选拔赛
A 树之荣荣 青梅熙熙 树之荣荣 青梅熙熙 这个题是一个经典的博弈问题。我们可以考虑一种情况,就是你每一次都会取一个。那么最后一个你肯定不能取。所以我们可以考虑减去一个后的值。判断它的和是奇数还是偶数即可。 int n; cin >> n;int s 0;for (int i 1;…...
设计模式|策略模式 Strategy Pattern 详解
目录 一、策略模式概述二、策略模式的实现2.1 策略接口2.2 具体策略类2.3 上下文类2.4 客户端代码2.5 UML类图2.6 UML时序图 三、优缺点3.1 ✅优点3.2 ❌ 缺点 四、最佳实践场景4.1 适合场景描述4.2 具体场景 五、扩展5.1 继承复用机制和复合策略5.2 对象管理:优化策…...
