qt-C++笔记之QThread使用

qt-C++笔记之QThread使用

——2024-05-26 下午

在这里插入图片描述

在这里插入图片描述

code review!

参考博文:
qt-C++笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面
qt-C++笔记之QThread使用

文章目录

  • qt-C++笔记之QThread使用
    • 一:Qt中几种多线程方法
      • 1.1. 使用 `QThread` 和 Lambda
      • 1.2. 使用 `QThread::create()`
      • 1.3. 继承 `QThread` 并重写 `run()`
      • 1.4. 使用 `QObject` 派生类与 `QThread`
      • 1.5. 使用 `QtConcurrent::run()`
      • 总结
    • 二.方法一:继承QThread并重写其run()方法
      • 2.1.代码一:运行全局纯函数
      • 2.2.代码二:运行全局纯函数
      • 2.3.代码一和代码二的区别
        • 2.3.1 带`input`参数的构造函数
        • 2.3.2. 带`input`和`parent`参数的构造函数
        • 2.3.3 总结
      • 2.4.代码三:直接在run()方法中写运行逻辑
      • 2.5.代码四:直接在run()方法中写运行逻辑,并在QCoreApplication::quit()前执行一些打印
      • 2.6.代码五:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数
      • 2.7.代码六:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数
    • 三.方法二:将任务放在QObject派生类中,并`moveToThread()`在QThread中运行这个QObject
      • 3.1. 代码一:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象
      • 3.2. 代码二:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象
    • 四.方法三:直接使用 QThread 和 Lambda
    • 五.方法四:`QThread::create(Qt 5.10 及以上)`
      • 5.1.提要
        • 5.1.1.QThread::create()代码一
        • 5.1.2.QThread::create()代码二
    • 六.方法五:`QtConcurrent::run()`

一:Qt中几种多线程方法

五种不同的多线程实现方法在Qt中的特点和适用场景:

方法描述优点缺点适用场景
直接使用 QThread 和 Lambda使用 QThread 对象和信号槽连接一个lambda表达式来执行代码。简单快速;灵活定义启动行为。精细控制线程较少;线程复用不便。快速实现简单的后台任务,不需要复用线程。
使用 QThread::create()使用 QThread::create() 创建并自动启动线程来执行函数或lambda。极简代码;自动线程管理。对线程的控制较为有限;不易于复用。适合快速启动一次性后台任务,不需要线程间交互。
继承 QThread 并重写 run()通过继承 QThread 并重写其 run() 方法来定义线程行为。完全控制线程行为;能够处理复杂逻辑。实现复杂;易误用(如直接操作GUI)。需要精细控制线程行为或有复杂线程逻辑的场景。
使用 QObject 派生类与 QThread创建 QObject 派生类,并在移至 QThread 的对象上执行任务。分离工作和线程管理;完全的信号和槽支持。设置相对繁琐;代码量较多。需要线程频繁与主线程通信或任务较为复杂的场景。
使用 QtConcurrent::run()使用Qt并发模块的 QtConcurrent::run() 在线程池中运行函数或成员函数。简单易用;自动管理线程池;减少资源消耗。对线程控制较少;不适合特定线程管理需求。适用于执行独立的并发任务,不需要细粒度线程控制。

1.1. 使用 QThread 和 Lambda

这种方法直接使用 QThread 的实例,并通过信号和槽系统将lambda表达式绑定至 QThread::started 信号。这种方法允许灵活地定义线程开始时执行的代码,而不需创建额外的类或使用 QtConcurrent。它适合快速简单的线程使用,尤其是当你不需要频繁与主线程通信或管理复杂的线程生命周期时。

1.2. 使用 QThread::create()

QThread::create() 是Qt 5.10引入的一个便捷函数,它基本上是创建线程与绑定任务的简化版。你只需要提供一个函数或lambda表达式,QThread::create() 会自动创建线程并在启动线程时执行这个函数。

auto thread = QThread::create([](){
    // 执行一些任务
});
thread->start();

这种方法的优点是极其简单,但它通常不适用于需要复杂线程管理或多次复用线程的场景。

1.3. 继承 QThread 并重写 run()

这是一种更传统的方法,通过继承 QThread 并重写其 run() 方法实现。这种方法提供了最大的灵活性,允许你控制线程的准确行为,但也需要更多的代码和复杂的错误处理。

class WorkerThread : public QThread
{
protected:
    void run() override {
        // 执行任务
    }
};

1.4. 使用 QObject 派生类与 QThread

这是Qt推荐的多线程使用方式。你创建一个 QObject 派生类来封装工作任务,然后将这个对象的实例移动到 QThread 中。

class Worker : public QObject
{
    Q_OBJECT
public slots:
    void doWork() {
        // 执行任务
    }
};

QThread *thread = new QThread();
Worker *worker = new Worker();
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);
thread->start();

这种方法适合需要线程与主线程频繁交互的场景,因为它完全兼容Qt的信号与槽机制。

1.5. 使用 QtConcurrent::run()

QtConcurrent::run() 是处理并发运算的另一种高级方法,它可以非常方便地在后台线程池中运行函数或成员函数。

QtConcurrent::run([](){
    // 执行某些操作
});

这种方法非常适合不需要细粒度控制线程行为的场景,且可以自动管理线程池,避免创建和销毁线程的开销。

总结

  • 直接使用 QThread 和 Lambda:适合快速、一次性的简单后台任务。
  • 使用 QThread::create():简化版的线程创建和任务绑定,适合不需要复用线程的场景。
  • 继承 QThread:适用于需要完全控制线程行为的复杂场景。
  • 使用 QObject 派生类与 QThread:Qt推荐的方式,适合需要线程间频繁通信的场景。
  • 使用 QtConcurrent::run():适用于简单并发任务,自动线程池管理,减少资源消耗。

二.方法一:继承QThread并重写其run()方法

2.1.代码一:运行全局纯函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数的定义,这个函数只进行计算并返回结果,不涉及任何的状态修改
int pureFunction(int x) {
    return x * x;
}

// 创建一个线程类,用于运行纯函数
class WorkerThread : public QThread {
public:
    WorkerThread(int input) : inputValue(input) {}

protected:
    void run() override {
        int result = pureFunction(inputValue);
        qDebug() << "计算结果:" << result;
    }

private:
    int inputValue;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 初始化一个线程对象,传入参数5
    WorkerThread thread(5);

    // 连接线程的finished信号到QCoreApplication的quit槽,确保应用程序在线程结束后退出
    QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);

    // 启动线程
    thread.start();

    // 进入事件循环
    return a.exec();
}

运行

计算结果: 25

2.2.代码二:运行全局纯函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 全局纯函数
void globalPureFunction(int param) {
    qDebug() << "运行在线程:" << QThread::currentThreadId();
    qDebug() << "接收到的参数:" << param;
    // 模拟一些处理过程
    QThread::sleep(2); // 假装我们在做一些耗时的工作
    qDebug() << "处理完成";
}

// 线程类
class WorkerThread : public QThread {
    int m_param;
public:
    WorkerThread(int param, QObject *parent = nullptr) : QThread(parent), m_param(param) {}

protected:
    void run() override {
        globalPureFunction(m_param); // 在新线程中调用全局纯函数
    }
};

// 主函数
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    int inputValue = 42; // 示例参数值
    WorkerThread *thread = new WorkerThread(inputValue);
    thread->start(); // 启动线程

    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit);

    return a.exec();
}

运行

运行在线程: 0x7fd2ea57f700
接收到的参数: 42
处理完成

2.3.代码一和代码二的区别

在Qt中,处理QThread和其他继承自QObject的类时,构造函数中的parent参数非常关键,它影响对象的内存管理和事件传递机制。让我们比较一下这两种构造函数的定义和它们的实际用途:

2.3.1 带input参数的构造函数
WorkerThread(int input) : inputValue(input) {}

这个构造函数只接受一个input参数,并初始化成员变量inputValue。这里没有显式地处理parent参数:

  • 作用:初始化inputValue
  • 内存管理:这个WorkerThread对象的生命周期需要显式管理(比如通过在堆上创建和删除,或者确保其作用域在使用中不会结束),因为没有父对象来自动管理它。
  • 适用场景:当你不需要将线程对象的生命周期与其他Qt对象关联时,或者当你想要通过代码显式管理线程的生命周期时使用。
2.3.2. 带inputparent参数的构造函数
WorkerThread(int input, QObject *parent = nullptr) : QThread(parent), inputValue(input) {}

这个构造函数接受一个input参数和一个可选的parent参数,默认为nullptr。它在初始化列表中调用了QThread的构造函数,传递了parent参数:

  • 作用:初始化inputValue并设置父对象。
  • 内存管理:如果指定了父对象(parent不为nullptr),这个WorkerThread对象的生命周期将由其父对象自动管理(父对象销毁时,它也会被销毁)。如果parentnullptr,则其生命周期需要手动管理。
  • 适用场景:当你希望线程的生命周期与某个Qt对象(如窗口或其他组件)绑定时使用。这样可以简化内存管理,使线程的生命周期与其父对象相匹配。
2.3.3 总结

添加parent参数的版本提供了更灵活的内存管理选项,允许线程对象以树形层次结构中的一部分被管理,这对于复杂的Qt应用程序来说非常有用。没有parent参数的版本则简单、直接,更适合生命周期管理相对明确或简单的场合。在实际应用中,选择哪种方式取决于你的具体需求和线程管理策略。

2.4.代码三:直接在run()方法中写运行逻辑

#include <QCoreApplication>
#include <QThread>
#include <iostream>

// WorkerThread 类,继承自 QThread
class WorkerThread : public QThread
{
public:
    WorkerThread(QObject *parent = nullptr) : QThread(parent) {}

    // 重载 run 方法
    void run() override {
        // 纯函数任务内容
        for (int i = 0; i < 10; ++i) {
            std::cout << "工作线程运行中: " << i << std::endl;
            QThread::sleep(1); // 模拟耗时操作,每次循环暂停1秒
        }
        std::cout << "工作线程结束运行。" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建 WorkerThread 对象
    WorkerThread thread;

    // 连接线程完成信号到退出槽,确保线程完成后应用程序退出
    QObject::connect(&thread, &WorkerThread::finished, &a, &QCoreApplication::quit);

    // 启动线程
    thread.start();

    // 进入 Qt 事件循环
    return a.exec();
}

运行

工作线程运行中: 0
工作线程运行中: 1
工作线程运行中: 2
工作线程运行中: 3
工作线程运行中: 4
工作线程运行中: 5
工作线程运行中: 6
工作线程运行中: 7
工作线程运行中: 8
工作线程运行中: 9
工作线程结束运行。

2.5.代码四:直接在run()方法中写运行逻辑,并在QCoreApplication::quit()前执行一些打印

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数,作为线程任务
void runTask() {
    for (int i = 0; i < 10; ++i) {
        QThread::sleep(1); // 模拟耗时任务
        qDebug() << "工作在线程 " << QThread::currentThreadId() << " 中执行: " << i;
    }
}

// 自定义的线程类
class TaskThread : public QThread {
    Q_OBJECT // 添加 Q_OBJECT 宏以支持信号和槽
public:
    TaskThread(QObject *parent = nullptr) : QThread(parent) {}

protected:
    void run() override {
        runTask(); // 在新线程中运行纯函数
        emit taskCompleted(); // 发射任务完成信号
    }

signals:
    void taskCompleted();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    TaskThread thread;
    QObject::connect(&thread, &TaskThread::taskCompleted, &a, [&]() {
        qDebug() << "任务完成,信号在主线程 " << QThread::currentThreadId() << " 中被处理";
        QCoreApplication::quit(); // 完成后退出程序
    });

    qDebug() << "主线程ID: " << QThread::currentThreadId();
    thread.start(); // 启动线程

    return a.exec();
}

#include "main.moc" // 如果你不是使用 qmake,确保 moc 处理这个文件

运行

主线程ID:  0x7f7e73b0d780
工作在线程  0x7f7e6ef9d700  中执行:  0
工作在线程  0x7f7e6ef9d700  中执行:  1
工作在线程  0x7f7e6ef9d700  中执行:  2
工作在线程  0x7f7e6ef9d700  中执行:  3
工作在线程  0x7f7e6ef9d700  中执行:  4
工作在线程  0x7f7e6ef9d700  中执行:  5
工作在线程  0x7f7e6ef9d700  中执行:  6
工作在线程  0x7f7e6ef9d700  中执行:  7
工作在线程  0x7f7e6ef9d700  中执行:  8
工作在线程  0x7f7e6ef9d700  中执行:  9
任务完成,信号在主线程  0x7f7e73b0d780  中被处理

2.6.代码五:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数,有传参
int square(int x) {
    return x * x;
}

// 继承QThread的类,重写run()函数
class MyThread : public QThread {
protected:
    void run() override {
        // 调用纯函数,并传参
        int result = square(x);
        qDebug() << "Result:" << result;
    }

public:
    int x;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建MyThread对象
    MyThread thread;

    // 在main函数中声明参数,并传入MyThread对象
    int param = 10;
    thread.x = param;

    // 启动MyThread对象
    thread.start();

    // 等待MyThread对象结束
    thread.wait();

    return a.exec();
}

运行

Result: 100

2.7.代码六:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数的声明
void pureFunction(int a, int b);

// 继承自 QThread 的类
class WorkerThread : public QThread {

public:
    // 构造函数
    WorkerThread(int a, int b, QObject *parent = nullptr) : QThread(parent), m_a(a), m_b(b) {}

protected:
    // 重写 run 方法
    void run() override {
        // 在新线程中调用纯函数
        qDebug() << "线程开始执行";
        pureFunction(m_a, m_b);
        qDebug() << "线程执行完成";
    }

private:
    int m_a, m_b;  // 成员变量,用于存储传递给纯函数的参数
};

// 纯函数的实现
void pureFunction(int a, int b) {
    // 执行一些计算或处理
    int result = a + b;
    qDebug() << "纯函数执行结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建 WorkerThread 对象,传递参数给纯函数
    WorkerThread thread(10, 20);
    // 启动线程
    thread.start();
    // 等待线程执行完成
    thread.wait();

    return a.exec();
}

运行

线程开始执行
纯函数执行结果: 30
线程执行完成

三.方法二:将任务放在QObject派生类中,并moveToThread()在QThread中运行这个QObject

3.1. 代码一:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象

// 包含必要的头文件
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// Worker 类定义
class Worker : public QObject {
    Q_OBJECT

public:
    Worker() {}
    virtual ~Worker() {}

public slots:
    void process() {
        // 输出当前线程信息
        qDebug() << "Worker thread running in thread:" << QThread::currentThreadId();
        // 模拟耗时操作
        QThread::sleep(3);
        qDebug() << "Worker process completed.";
        emit finished();
    }

signals:
    void finished();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建线程对象
    QThread workerThread;
    Worker worker;

    // 将 worker 对象移动到新建的线程
    worker.moveToThread(&workerThread);

    // 连接信号和槽
    QObject::connect(&workerThread, &QThread::started, &worker, &Worker::process);
    QObject::connect(&worker, &Worker::finished, &workerThread, &QThread::quit);
    QObject::connect(&worker, &Worker::finished, &worker, &Worker::deleteLater);
    QObject::connect(&workerThread, &QThread::finished, &workerThread, &QThread::deleteLater);

    // 启动线程
    workerThread.start();

    // 运行事件循环
    int result = a.exec();

    // 等待线程结束
    workerThread.wait();

    return result;
}

#include "main.moc"

运行

Worker thread running in thread: 0x7f1943a36700
Worker process completed.
double free or corruption (out)
15:43:36: The program has unexpectedly finished.

3.2. 代码二:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// Worker类,负责执行实际的计算
class Worker : public QObject {
    Q_OBJECT

public:
    Worker(int a, int b) : m_a(a), m_b(b) {}

public slots:
    void process() {
        int result = m_a + m_b;  // 简单的加法计算
        qDebug() << "计算结果:" << result;
        emit finished();
    }

signals:
    void finished();

private:
    int m_a;
    int m_b;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    int value1 = 5, value2 = 3;
    Worker *worker = new Worker(value1, value2);
    QThread *thread = new QThread;

    // 将worker移动到线程
    worker->moveToThread(thread);

    // 连接信号和槽
    QObject::connect(thread, &QThread::started, worker, &Worker::process);
    QObject::connect(worker, &Worker::finished, thread, &QThread::quit);
    QObject::connect(worker, &Worker::finished, worker, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit); // 确保应用退出

    // 启动线程
    thread->start();

    return a.exec();
}

#include "main.moc"

运行

计算结果: 8

四.方法三:直接使用 QThread 和 Lambda

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数定义,用于计算两个整数的和
int add(int a, int b) {
    return a + b;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建线程对象
    QThread* thread = new QThread;
    int x = 3, y = 4;

    // 将任务移至线程,使用lambda表达式
    QObject::connect(thread, &QThread::started, [=]() mutable {
        int result = add(x, y);
        qDebug() << "The sum of" << x << "and" << y << "is" << result;
        thread->quit();  // 线程任务完成,请求退出线程
    });

    // 清理线程资源
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    // 启动线程
    thread->start();

    return a.exec();
}

运行

The sum of 3 and 4 is 7

五.方法四:QThread::create(Qt 5.10 及以上)

5.1.提要

  • 直接在 QThread类中没有提供直接创建并启动线程执行特定函数的方法(例如 QThread::create 是 C++11 后Qt 5.10 添加的功能,如果您使用的Qt版本较旧,这一功能可能不可用)

  • 在Qt中使用QThread来运行一个全局纯函数是一个比较通用的任务,在Qt中,通常通过继承QThread并重写run()方法来实现这一点,但使用QThread的能力来直接启动一个线程执行我们的函数。

5.1.1.QThread::create()代码一
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

void performCalculation(int a, int b) {
    int result = a + b;
    qDebug() << "计算结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    QThread *thread = QThread::create(performCalculation, 5, 3);
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    thread->start();

    return app.exec();
}
5.1.2.QThread::create()代码二
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 全局纯函数
void performCalculation(int a, int b) {
    int result = a + b;  // 简单的加法计算
    qDebug() << "计算结果:" << result;
}

// 线程执行的函数
void runInThread(int a, int b) {
    // 创建线程对象
    QThread* thread = QThread::create([=](){
        performCalculation(a, b);
    });

    // 连接线程结束信号到删除槽,确保资源被清理
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    // 启动线程
    thread->start();
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 在线程中执行全局函数
    runInThread(5, 3);

    return a.exec();
}

六.方法五:QtConcurrent::run()

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QtConcurrent>

// 全局纯函数
void performCalculation(int a, int b) {
    int result = a + b;  // 简单的加法计算
    qDebug() << "在线程" << QThread::currentThreadId() << "计算结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 使用QtConcurrent运行全局函数
    int value1 = 5, value2 = 3;
    QFuture<void> future = QtConcurrent::run(performCalculation, value1, value2);

    // 等待任务完成
    future.waitForFinished();

    return app.exec();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/645565.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gnocchi学习小结

背景 总结gnocchi 4.4版本gnocchi-metricd工作流程 入口 gnocchi.cli.metricd metricd stop after processing metric默认为0&#xff0c;调servicemanager run MetricdServiceManager __init__ 服务逻辑封装到MetricdServiceManager初始化中 主要由MetricProcessor, Met…

火山引擎“奇袭”阿里云

图片&#xff5c;电影《美国队长3》剧照 ©自象限原创 作者丨程心 编辑丨罗辑 大模型价格战&#xff0c;已经不是什么新闻。 从OpenAI发布GPT-4o&#xff0c;将API价格下调50%&#xff0c;并宣布面向普通用户免费开始&#xff0c;就标志着大模型的竞争从性能进入到了成本…

Java设计模式 _行为型模式_迭代器模式

一、迭代器模式 1、迭代器模式 迭代器模式&#xff08;Iterator Pattern&#xff09;是一种行为型设计模式&#xff0c;用于顺序访问集合对象的元素&#xff0c;不需要关心集合对象的底层表示。如&#xff1a;java中的Iterator接口就是这个工作原理。 2、实现思路 &#xff0…

面试大杂烩之kafka

面试这个领域最近环境不行&#xff0c;所以卷起来流量挺大 搭建&#xff1a; 总体来说 比较简单&#xff0c;主要是配置文件&#xff0c;命令的话分开了producer /consumer/ topic 大概这么个意思。具体可以看里面的博客 #host配置 #安装包 wget https://archive.apache.or…

国内最受欢迎的7大API供应平台对比和介绍||电商API数据采集接口简要说明

本文将介绍7款API供应平台&#xff1a;聚合数据、百度APIStore、Apix、数说聚合、通联数据、HaoService、datasift 。排名不分先后&#xff01; 免费实用的API接口 第一部分 1、聚合数据&#xff08;API数据接口_开发者数据定制&#xff09; 2、百度API Store(API集市_APIStore…

C++第十九弹---string模拟实现(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、修改操作 2、迭代器操作 3、字符串操作 4、非成员函数重载操作 总结 1、修改操作 1、string& operator (const char* s); //尾部插入…

骑行 - 新区永旺出发的环太湖路线

环过好几次太湖&#xff0c;但对路线都没太在意&#xff0c;都是跟着别人走的。这次自己制定一个路书&#xff0c;方便下次自己一个人环太湖时使用。 开始是使用高德地图做路书&#xff0c;只能在PC上做。我用的是网页版&#xff0c;每次选点太麻烦了。要输入地址搜索&#xff…

【C语言】八进制、十六进制

前言 在我们日常生活中使用的数往往是十进制的&#xff0c;而当我们学习C语言后我们会接触到许多不同的进制并且时常需要去思考与使用这些不同的进制&#xff08;尤其是2的幂相关的进制&#xff0c;因为这种计数系统比十进制更接近于计算机的二进制系统&#xff09;&#xff0…

5.26机器人基础-空间描述和变换2

在前文的基础上引入平移算子和旋转算子 1.平移算子 2.旋转算子 3.变换算子

推荐一款媒体影音嗅探神器—Chrome扩展插件(猫抓cat-catch)

目录 1.1、前言1.2、下载地址1.3、github Releases 版本说明1.4、安装步骤1.5、猫抓插件常规设置1.5.1、设置抓取文件的类型1.5.2、设置抓取文件的后缀名 1.1、前言 我们在日常上网的过程中&#xff0c;很多音频、视频网站下载资源都非常不方便&#xff0c;要么需要安装客户端&…

联邦学习(一)

世界第一本“联邦学习”专著——《联邦学习》。作者阅读数书籍《联邦学习实战》。 1.联邦学习概述 在构件全局模型时,其效果与数据被整合在一起进行集中式训练的效果几乎一致,这便是联邦学习提出的动机和核心思想。 核心理念:数据不动模型动,数据可用不可见。 传统训练范式…

初步认识栈和队列

Hello&#xff0c;everyone&#xff0c;今天小编讲解栈和队列的知识&#xff01;&#xff01;&#xff01; 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&…

hsql学习笔记

1. row_number() over (partition by uid order by dt 分析&#xff1a; row_number()&#xff1a; 这是一个窗口函数&#xff0c;用于为结果集中的每一行分配一个唯一的序号。默认情况下&#xff0c;这个序号是按照查询结果的顺序来分配的&#xff0c;但你可以通过OVER()子句…

Mybatis源码剖析---第二讲

Mybatis源码剖析—第二讲 那我们在讲完了mappedstatement这个类&#xff0c;它的一个核心作用之后呢&#xff1f;那下面我有一个问题想问问各位。作为mappedstatement来讲&#xff0c;它封装的是一个select标签或者insert标签。但是呢&#xff0c;我们需要大家注意的是什么&am…

文件夹打开出错?这里有你需要的数据恢复与预防指南

在日常使用电脑时&#xff0c;我们有时会遇到文件夹打开出错的情况。当你尝试访问某个文件夹时&#xff0c;系统可能会弹出一个错误提示&#xff0c;告诉你无法打开该文件夹。这种情况不仅会影响我们的工作效率&#xff0c;还可能导致重要数据的丢失。接下来&#xff0c;我们将…

Java进阶学习笔记24——Object类

Object类: Object类是Java中所有类的祖宗类&#xff0c;因此&#xff0c;Java中所有类的对象都可以直接使用Object类中提供的一些方法。 所有类都是Object类的子孙类。 API文档&#xff1a; Object类的成员方法&#xff1a; Object类的常见方法&#xff1a; Student类&…

HCIP-Datacom-ARST自选题库_02_网络安全【道题】

一、单选题 1.关于网络安全性优化的内容&#xff0c;下列哪个选项是错误的? 管理安全 边界安全 访问控制 日志管理 2.如图所示&#xff0c;网络管理员为了抵御DHcP Server仿冒者攻击&#xff0c;在交换机上部署了DHcp snoping功能&#xff0c;那么以下哪一个接口应该被设…

简单的python程序,把它做成docker镜像

1&#xff0c;python程序准备 在linux主机的/tmp/pythontest路径下创建一个test.py程序文件&#xff0c; 程序内容很简单 就是一句打印 print(hello world, docker)2&#xff0c;再准备一个Dockerfile文件 这个Dockerfile也是放在主机linux中的/tmp/pythontest路径下&#x…

RPA+AI 应用案例集合:自动推流直播

使用场景&#xff1a; 自动定时推流直播 使用技术&#xff1a; python playwright 每个解决一个小问题 During handling of the above exception, another exception occurred:Traceback (most recent call last): File "D:\pythonTryEverything\putdonwphone\not_watch_…

队列(C语言)

文章目录 [TOC](文章目录) 前言1.队列的概念及结构2.队列的实现3.相关操作的具体实现3.1.初始化队列(QueueInit)和销毁队列(QueueDestory)3.2.队尾入队(QueuePush)和队头出队(QueuePop)3.3.判空(QueueEmpty)、获得队尾元素(QueueBack)以及获得队头元素(QueueFront) 前言 前面我…