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 引入的一种新的引用类型,用 && 表示。它主要用于区分左值和右值,并且可以实现移动语义,避免不必要的深拷贝,提高程序的性能。左值通常是可以取地址的表达式…...
Leetcode 1477. 找两个和为目标值且不重叠的子数组 前缀和+DP
原题链接: Leetcode 1477. 找两个和为目标值且不重叠的子数组 class Solution { public:int minSumOfLengths(vector<int>& arr, int target) {int narr.size();int sum0;int maxnINT_MAX;vector<int> dp(n,maxn);//dp[i]表示以索引i之前的满足要求…...
koa-session设置Cookie后获取不到
在谷歌浏览器中请求获取不到cookie问题之一(谷歌安全策略) 场景 前端使用 axios 请求,项目地址:http://192.168.8.1:5173 import axios from axiosconst request axios.create({baseURL: http://127.0.0.1:3001/,timeout: 60000,…...
Linux三种网络方式
前言 发现运维啥都得会,这周就遇到了网络问题自己无法解决,因此痛定思痛学一下。 参考文献 你管这破玩意叫网络? 桥接模式、NAT模式、仅主机模式,原来是这样工作的 交换机 构成局域网,实现所有设备之间的通信。 …...
android_viewtracker 原理
一、说明 我们业务中大部分场景是用 RecyclerView 实现的列表,而 View 的曝光通常是直接写在 adapter 的 onBindViewHolder 中,这样就会导致 item 还没显示出来的时候就会触发曝光。最近业务提出需要实现根据 View 显示在屏幕上面积大于 80% 才算曝光。…...
Object.defineProperty()
**Object.defineProperty()** 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 plain const object1 {}; Object.defineProperty(object1, ‘property1’, { value: 42, writable: false }); object1.property1 77…...
大模型+知识图谱:重塑企业制度标准管理
在数字化转型的浪潮中,制度标准管理领域正迎来一场革命性的变革。借助大模型和知识图谱等前沿人工智能技术,制度标准管理不再仅仅是简单的文档存储和检索,而是演变为一个智能化、高效化、精准化的管理体系。 1.关键技术 我们的制度标准管理…...
ubuntu20系统下conda虚拟环境下安装文件存储位置
在 Conda 虚拟环境中执行 pip install 安装软件后,安装的文件会存储在该虚拟环境专属的 site-packages 目录中。具体路径取决于你激活的 Conda 环境路径。以下是定位步骤: 1. 确认 Conda 虚拟环境的安装路径 查看所有环境: conda info --env…...
深度学习编译器(整理某survey)
一、深度学习框架 TensorFlow PyTorch MXNet ONNX:定义了一个统一的表示,DL models的格式方便不同框架之间的转换模型 二、深度学习硬件 通用硬件(CPU、GPU):通过硬件和软件优化支持深度学习工作负载 GPU:通过多核架构实现高…...
Python学习第八天
查看函数参数 操作之前给大家讲一个小技巧:如何查看函数的参数(因为python的底层源码是C语言并且不是开放的,也一直困扰着刚学习的我,这个参数叫什么名之类的看doc又总是需要翻译挺麻烦的)。 比如我们下面要说到的op…...
SpringBoot为什么默认使用CGLIB?
大家好,我是锋哥。今天分享关于【SpringBoot为什么默认使用CGLIB?】面试题。希望对大家有帮助; SpringBoot为什么默认使用CGLIB? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 默认使用 CGLIB(Code Generation Li…...
【消息队列】数据库的数据管理
1. 数据库的选择 对于当前实现消息队列这样的一个中间件来说,具体要使用哪个数据库,是需要稍作考虑的,如果直接使用 MySQL 数据库也是能实现正常的功能,但是 MySQL 也是一个客户端服务器程序,也就意味着如果想在其他服…...
pytest中pytest.ini文件的使用
pytest.ini 是 pytest 测试框架的配置文件,它允许你自定义 pytest 的行为。通过在 pytest.ini 中设置各种选项,可以改变测试用例的发现规则、输出格式、插件行为等。以下详细介绍 pytest.ini 文件的使用。 1. 文件位置 pytest.ini 文件通常位于项目的根目录下,pytest 在运…...
docker学习笔记(1)从安装docker到使用Portainer部署容器
docker学习笔记第一课 先交代背景 docker宿主机系统:阿里云ubuntu22.04 开发机系统:win11 docker镜像仓库:阿里云,此阿里云与宿主机系统没有关系,是阿里云提供的一个免费的docker仓库 代码托管平台:github&…...
Vue.js侦听器
侦听器 基本示例 计算属性允许我们声明性地计算衍生值。然而在有些情况下,我们需要在状态变化时执行一些“副作用”:例如更改 DOM,或是根据异步操作的结果去修改另一处的状态。 在组合式 API 中,我们可以使用 watch 函数在每次响应式状态发生变化时触发回调函数: …...
【C++学习篇】智能指针
目录 1. 智能指针的使用场景分析 2. RAII和智能指针的设计思路 3. C标准库智能指针的使用 4.shared_ptr和weak_ptr 4.1shared_ptr的循环引用问题 4.2 weak_ptr 1. 智能指针的使用场景分析 下⾯程序中我们可以看到,new了以后,我们也delete了,…...
数字电子技术基础(二十四)——TTL门电路的高、低电平的输出特性曲线
目录 1 TTL门电路的特性曲线 1.1 高电平输出特性 1.1.2 高电平输出特性的实验过程 1.1.2 TTL门电路的输出特性的实验结果 1.2 低电平的输出特性 1 TTL门电路的特性曲线 1.1 高电平输出特性 1.1.2 高电平输出特性的实验过程 现在想要测试TTL门电路的输出特性,…...
linux进程通信之共享内存
在 Linux 系统中,共享内存(Shared Memory) 是一种高效的进程间通信(IPC)方式,允许多个进程直接访问同一块物理内存区域。以下是关于 Linux 共享内存的详细讲解: 一、共享内存的核心特点 高速通信…...
学习第十一天-树
一、树的基础概念 1. 定义 树是一种非线性数据结构,由 n 个有限节点组成层次关系集合。特点: 有且仅有一个根节点其余节点分为若干互不相交的子树节点间通过父子关系连接 2. 关键术语 术语定义节点包含数据和子节点引用的单元根节点树的起始节点&#…...
场景题:10亿QQ用户,如何统计在线人数?
现在卷的环境下,面试除了八股文算法项目外,场景题也是问的越来越多了。一方面是就业市场竞争者较多所带来的必然结果;另一方面是公司对于应聘者的技术要求也越来越高了。 今天继续介绍Java面试常见的场景题:在线人数统计 现在用户…...
学习工具的一天之(burp)
第一呢一定是先下载 【Java环境】:Java Downloads | Oracle 下来是burp的下载 Download Burp Suite Community Edition - PortSwigger 【下载方法二】关注的一个博主 【BurpSuite 安装激活使用详细上手教程 web安全测试工具】https://www.bilibili.com/video/BV…...
归并排序:分治哲学的完美演绎与时空平衡的艺术
引言:跨越世纪的算法明珠 在计算机科学的璀璨星河中,归并排序犹如一颗恒久闪耀的明星。1945年,现代计算机之父冯诺伊曼在EDVAC计算机的研发过程中首次系统性地提出了这一算法,其精妙的分治思想不仅奠定了现代排序算法的理论基础&…...
蓝桥杯4T平台(串口打印电压值)
知识点:串口(单片机发送数据)按键ADC 题目 配置 代码 adc.c uint16_t getadc2(void) {uint16_t adc0;HAL_ADC_Start(&hadc2);adcHAL_ADC_GetValue(&hadc2);return adc; } adc.h uint16_t getadc2(void); main.c #include "lcd.h" #include…...
Stable Diffusion Prompt编写规范详解
Stable Diffusion Prompt编写规范详解 一、语法结构规范 (一)基础模板框架 [质量强化] [主体特征] [环境氛围] [风格控制] [镜头参数]质量强化:best quality, ultra detailed, 8k resolution主体特征:(1girl:1.3), long …...
es6常见知识点
官方文档:[https://es6.ruanyifeng.com/](https://es6.ruanyifeng.com/) 一、Class 1、Class Class只是一个语法糖,其功能用es5也能实现,但是比es5更符合类的期待 定义: constructor代表构造方法,而this指向new 生成的实例 定义类方法时,可以不使用function 注…...
leetcode1 两数之和 哈希表
什么时候使用哈希法,当我们需要查询一个元素是否出现过,或者一个元素是否在集合里的时候,就要第一时间想到哈希法。 242. 有效的字母异位词 (opens new window)这道题目是用数组作为哈希表来解决哈希问题,349. 两个数组的交集 (o…...
Java中lombok的@Data注解【布尔类型】字段定义方式
文章目录 背景第一步、场景复现第二步、分析问题第三步、实现方案总结 背景 在Data注解的bean中添加Boolean字段时,set方法正常,get方法无法获取。 第一步、场景复现 在OrderInfo的实体中,新增布尔类型的字段:支付过【hasPaid】…...
理解数学概念——稠密性(density)
目录 1. 定义 2. 等价定义 3. 直观理解 1. 定义 在拓扑学(topology)和数学相关领域中,对于一个拓扑空间 X 的一个子集 A,若 X的每一个点要么属于A ,要么无限“接近”X的某个成员,则称这个子集 A 是稠密的(dense)或称A具有稠密性…...
【Spring AOP】_切点类的切点表达式
目录 1. 根据方法签名匹配编写切点表达式 1.1 具体语法 1.2 通配符表达规范 2. 根据注解匹配编写切点表达式 2.1 实现步骤 2.2 元注解及其常用取值含义 2.3 使用自定义注解 2.3.1 编写自定义注解MyAspect 2.3.2 编写切面类MyAspectDemo 2.3.3 编写测试类及测试方法 在…...
通过多线程获取RV1126的AAC码流
目录 一RV1126多线程获取音频编码AAC码流的流程 1.1AI模块的初始化并使能 1.2AENC模块的初始化 1.3绑定AI模块和AENC模块 1.4多线程获取每一帧AAC码流 1.5每个AAC码流添加ADTSHeader头部 1.6写入具体每一帧AAC的…...
HDFS 为什么不适合处理小文件?
目录 一、HDFS 是什么? 1. 核心目标 2. 基本架构 二、HDFS 为什么不适合处理小文件? 1. 元数据管理问题 2. 存储效率低下 3. 访问性能问题 4. 计算框架效率问题 5. 其他限制 一、HDFS 是什么? HDFS(Hadoop 分布式文件系统…...
网络空间安全(14)编辑器漏洞
一、概述 网页在线编辑器允许用户在网页上进行文本的编辑,并设置字体样式、段落行间距等,类似于使用Word进行编辑。然而,由于编辑器在处理用户输入、文件上传、权限控制等方面可能存在安全缺陷,因此容易成为攻击者利用的目标。 二…...
SpringMvc与Struts2
一、Spring MVC 1.1 概述 Spring MVC 是 Spring 框架的一部分,是一个基于 MVC 设计模式的轻量级 Web 框架。它提供了灵活的配置和强大的扩展能力,适合构建复杂的 Web 应用程序。 1.2 特点 轻量级:与 Spring 框架无缝集成,依赖…...
Avalonia 打包成deb
参考 https://www.cnblogs.com/Fengyinyong/p/13346642.html 安装工具 dotnet tool install --global dotnet-deb 还原包 dotnet restore -r linux-x64 dotnet deb install 打包,其中/p:SelfContainedtrue是独立运行 dotnet msbuild XXXCore.csproj /t:Creat…...
服务器数据恢复—raid5阵列中硬盘掉线导致上层应用不可用的数据恢复案例
服务器数据恢复环境&故障: 某公司一台服务器,服务器上有一组由8块硬盘组建的raid5磁盘阵列。 磁盘阵列中2块硬盘的指示灯显示异常,其他硬盘指示灯显示正常。上层应用不可用。 服务器数据恢复过程: 1、将服务器中所有硬盘编号…...
除了合并接口,还有哪些优化 Flask API 的方法?
除了合并接口,还有许多其他方法可以优化 Flask API,以下从性能优化、代码结构优化、安全性优化、错误处理优化等方面详细介绍: 性能优化 1. 使用缓存 内存缓存:可以使用 Flask-Caching 扩展来实现内存缓存,减少对数…...
制服小程序的“滑手”:禁用页面左右滑动全攻略
哈哈,看来你已经很聪明地发现了小程序中左右滑动的“顽皮”行为!😄 没错,我们可以通过设置 disableScroll 属性来“管教”它,同时结合 CSS 样式让页面既禁得住横向“乱跑”,又能顺畅地上下滚动。你的方案已…...
学习日记-250305
阅读论文:Leveraging Pedagogical Theories to Understand Student Learning Process with Graph-based Reasonable Knowledge Tracing ps:代码逻辑最后一点还没理顺,明天继续 4.2 Knowledge Memory & Knowledge Tracing 代码研究: 一般…...
DeepSeek R1模型医疗机构本地化部署评估分析(Discuss V1版上)
为了确保医疗机构在部署和应用DeepSeek R1模型时的成功,可以根据各个步骤设计一套综合的评估和评测体系。该体系将帮助医疗机构在实施过程中持续跟踪效果、识别潜在问题并进行优化调整。以下是对各步骤的详细评估和评测体系设计。 1. 确定模型需求 在医疗机构上线DeepSeek R…...
java 查找连个 集合的交集部分数据
利用了Java 8的Stream API,代码简洁且效率高 import java.util.stream.Collectors; import java.util.List; import java.util.HashSet; import java.util.Set;public class ListIntersection {public static List<Long> findIntersection(List<Long> …...
Hadoop管理页看不到任务的问题
这个yarn分配任务了但是为空 在$HADOOP_HOME/conf/mapred-site.xml 原来的配置文件基础之上添加: <property><name>mapreduce.framework.name</name><value>yarn</value></property> 重启之后就好了...
cmake、CMakeLists.txt、make、ninja
文章目录 一、概念0.cmake官网1.什么是cmake2.为什么使用cmake3.CMakeLists.txt 二、CMakeLists.txt语法:如何编写CMakeLists.txt,语法详解(0)语法基本原则(1)project关键字(2)set关键字(3)message关键字(4)add_executable关键字(5)add_subdirectory关键…...
PHP之Cookie和Session
在你有别的编程语言的基础下,你想学习PHP,可能要了解的一些关于cookie和session的信息。 Cookie 参数信息 setcookie(name,value,expire, path, domain); name : Cookie的名称。 value : Cookie的值。 expire : Cookie的过期时间,可以是一…...
学习记录-用例设计编写
黑马测试视频记录 目录 一、 软件测试流程 二、测试用例编写格式 1、等价类法 2、边界值分析法 3、 判定表法 4、场景法编辑 5、错误推荐法 一、 软件测试流程 二、测试用例编写格式 1、等价类法 2、边界值分析法 3、 判定表法 4、场景法 5、错误推荐法 时间紧任务重…...
【Docker】容器安全之非root用户运行
【Docker】容器安全之非root用户运行 1. 场景2. 原 Dockerfile 内容3. 整改结果4. 非 root 用户带来的潜在问题4.1 文件夹读写权限异常4.2 验证文件夹权限 1. 场景 最近有个项目要交付,第三方测试对项目源码扫描后发现一个问题,服务的 Dockerfile 都未指…...
CVE-2025-0392:JeeWMS graphReportController.do接口SQL注入漏洞复现
文章目录 CVE-2025-0392:JeeWMS graphReportController.do接口SQL注入漏洞复现0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.构造POC2.复现CVE-2025-0392:JeeWMS graphReportController.do接口SQL注入漏洞复现 0x01 前言 免责声明:请勿利用文章内的相…...
如何使用 Python+Flask+win32print 实现简易网络打印服务1
Python 实现网络打印机:Flask win32print 在工作场景中,我们可能需要一个简单的网页接口,供他人上传文档并自动打印到指定打印机。 本文将演示如何使用 Python Flask win32print 库来实现这一需求。 代码详见:https://github.…...
Ubuntu20.04双系统安装及软件安装(十一):向日葵远程软件
Ubuntu20.04双系统安装及软件安装(十一):向日葵远程软件 打开向日葵远程官网,下载图形版本: 在下载目录下打开终端,执行: sudo dpkg -i SunloginClient(按tab键自动补全)出现报错: …...
鸿蒙启动页开发
鸿蒙启动页开发 1.1 更改应用名称和图标 1.更改应用图标 找到moudle.json5文件,找到应用启动的EntryAbility下面的icon,将原来的图标改成自己设置的即可 2.更改应用名称 3.效果展示 2.1 广告页面开发 3.1 详细介绍 3.1.1 启动页面 import { PrivacyDialog } fr…...
认知动力学视角下的生命优化系统:多模态机器学习框架的哲学重构
认知动力学视角下的生命优化系统:多模态机器学习框架的哲学重构 一、信息熵与生命系统的耗散结构 在热力学第二定律框架下,生命系统可视为负熵流的耗散结构: d S d i S d e S dS d_iS d_eS dSdiSdeS 其中 d i S d_iS diS为内部熵…...