(个人使用)C++和QT技巧汇总

持续更新中。。。

一、C++篇

设计模式

1. 单例

1.1 单例写法1
class Singleton {
public:
    static Singleton& GetInstance() {
        static Singleton instance;
        return instance;
    }

private:
    Singleton() {};  // 私有化构造函数,防止外部创建实例

    Singleton(const Singleton&);  // 禁止拷贝构造函数
    Singleton& operator=(const Singleton&);  // 禁止赋值操作符重载
};

因为是static修饰过的,所以通过调用 Singleton::GetInstance() 可以获取到唯一实例的引用,并且保证了在整个程序中只有一个实例存在。

1.2 单例写法2
class Singleton:
{
    // 其它成员
public:
    static Singleton * GetInstance()
    {
        if (m_pInstance == NULL)
            m_pInstance = new Singleton();
        return m_pInstance;
    }
 
private:
    Singleton(){};
    static Singleton * m_pInstance;
}
# 缺点:需要手动释放
1.3 单例模式3
class Singleton:
{
    // 其它成员
public:
    static Singleton * GetInstance(){...}
private:
    Singleton(){};
    static Singleton * m_pInstance;
 
    class CGarbo // 它的唯一工作就是在析构函数中删除Singleton的实例
    {
    public:
        ~CGarbo(){
            if (Singleton::m_pInstance)
                delete Singleton::m_pInstance;
        }
    };
 
    static CGarbo Garbo; // 定义一个静态成员,在程序结束时,系统会调用它的析构函数
}

会自动释放,但是不美观,还是第一种好。

但是无论哪种,在多线程的时候,都有问题,需要加锁。

2. 智能指针

2.1 make_shared创建智能指针

std::make_shared是C++标准库中的一个模板函数,用于创建指定类型的shared_ptr智能指针对象。它提供了一种便捷的方式来创建和管理动态分配的对象。

std::make_shared函数的定义如下:

template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);

使用std::make_shared函数有以下优点:

  1. 更高的性能:std::make_shared一次性分配了内存空间来存储对象和引用计数,相比于先使用new运算符创建对象再传递给shared_ptr,可以减少一次内存分配,提高性能。
  2. 更安全的异常处理:如果在创建对象时抛出异常,std::make_shared会确保释放已分配的内存,避免内存泄漏。
  3. 简化的语法:std::make_shared可以通过自动推断对象类型,无需显式指定模板参数。

下面是一个使用std::make_shared的示例:

#include <memory>

struct MyClass {
    int value;
    MyClass(int val) : value(val) {}
};

int main() {
    auto ptr = std::make_shared<MyClass>(42);
    // 使用ptr访问MyClass对象
    return 0;
}

3. 等待一段时间

3.1 当前线程等待
#include <chrono>
#include <thread>

std::this_thread::sleep_for(std::chrono::milliseconds(1000));

4. 线程相关

4.1 打印线程ID
#include <iostream>
#include <thread>
using namespace std;
cout << "子线程中显示子线程id为" << this_thread::get_id()<< endl;
4.2 C++线程写法

(随记)C++多线程的简单Demo_c++ 多线程demo-CSDN博客

二、QT篇

1. 全局信号类

头文件:globalSignal.h

#ifndef GLOBALSIGNAL_H
#define GLOBALSIGNAL_H

#include <QObject>

class GlobalSignal : public QObject
{
    Q_OBJECT
public:
    //获取单实例
    static GlobalSignal* getInstance();
    //释放单实例
    static void deleteInstance();

signals:
    void dataReceived(const QString& data);
    void getValue(int value);

private:
    //单实例对象指针
    static GlobalSignal *globalSignal;

    //构造、析构、拷贝构造、赋值构造私有
    GlobalSignal(){};
    ~GlobalSignal(){};
    GlobalSignal(const GlobalSignal &){};
    const GlobalSignal &operator=(const GlobalSignal &){};

};

#endif // GLOBALSIGNAL_H

// 使用方式:
// 1. 引入头文件,在私有对象中添加 GlobalSignal *glbSignal;
//
// 2. 构造函数中创建:glbSignal = GlobalSignal::getInstance();
//
// 3. 触发方式:
// 	emit glbSignal->getValue(num);
// 4. 接收方式:
//  connect(glbSignal,&GlobalSignal::getValue,this,[=](int value){
//          QString msg = QString("接收到数据:nn:%1").arg(value);
//          ui->textBrowser->append(msg);
//  });

cpp文件:

#include "globalSignal.h"

//全局信号转发单例类: 饿汉式
GlobalSignal* GlobalSignal::globalSignal = new GlobalSignal();

GlobalSignal *GlobalSignal::getInstance()
{
    return globalSignal;
}

void GlobalSignal::deleteInstance()
{
    if(globalSignal)
    {
        delete globalSignal;
        globalSignal = nullptr;
    }
}

2. 几种多线程方式

详细链接:QT中,QT线程四种写法的对比和写法示例-CSDN博客

2.1 moveToThread
  • 自己写一个继承自QObject的类调用方式:这个是测试的,很多都可以删掉
#include <QObject>
#include <QDebug>
#include <QThread>
​
class MyWorker : public QObject
{
    Q_OBJECT
public:
    explicit MyWorker(QObject *parent = nullptr);
    ~MyWorker();
private:
    void func(const QString& cmd);
public slots:
    void doSomething(const QString& cmd);
    void doThis();
signals:
    void resultNotify(const QString& des);  // 结束信号
private:
    bool flag = true;
    int  num = 10;
};
​
// ***************************************
​
MyWorker::MyWorker(QObject *parent) : QObject(parent)
{
    qDebug() << "Worker()" << "thread:" << QThread::currentThreadId();
}
​
MyWorker::~MyWorker()
{
    qDebug() << "~Worker()" << "thread:" << QThread::currentThreadId();
}
​
void MyWorker::func(const QString &cmd = "test")
{
    qDebug() << "func()" << "thread:" << QThread::currentThreadId();
    while (num--) {
        qDebug()<<"func:"<<cmd;
        QThread::sleep(1);
    }
    emit resultNotify(cmd);
}
​
void MyWorker::doSomething(const QString &cmd)
{
    qDebug() << "doSomething()" << "thread:" << QThread::currentThreadId();
    flag = true;
    func(cmd);
}
​
void MyWorker::doThis()
{
    qDebug() << "doThis()" << "thread:" << QThread::currentThreadId();
    int n=10;
    while (n--) {
        qDebug()<<"doThis:";
        QThread::sleep(1);
    }
}
  • 调用方式1:必须使用信号触发
# 这个写在头文件:
QThread  myWorkThread;
MyWorker myWorker;

# 这个写构造函数里面
myWorker.moveToThread(&myWorkThread);
myWorkThread.start();

# 调用方式:------------------------------------------------

    // 方式一:直接调用,还是主线程,千万别这么用!!!
    // myWorker.doSomething("test");
​
    // 方式二:信号关联
    // 带参数:
    connect(this,&MainWindow::doSomething,&myWorker,&MyWorker::doSomething);
    emit doSomething("test");
​
    // 不带参数:
    connect(this,&MainWindow::doThis,&myWorker,&MyWorker::doThis);
    emit doThis();
  • 调用方式2:像使用普通函数一样
myThread = new QThread();
myworker = new Worker();
myworker->moveToThread(myThread);
myThread->start();

//myworker.init();    // 还是主线程,别用
 
// 一般的调用方法:
connect(this,&MainWindow::doInit,myworker,&Worker::init);
emit doInit();
 
// 简化写法:
QMetaObject::invokeMethod(myworker,"init");
2.2 QtConcurrent快速开启线程
有的版本可能需要在pro中,添加 QT += concurrent ,未测试。我发现我不加也能用。

调用方式:

1. QFuture<void> future = QtConcurrent::run(&worker, &Worker::doWork);

2. QtConcurrent::run([=](){    worker->UDPtest("直接调用即可"); });
或者:
QtConcurrent::run([=](){
    worker->UDPtest("UDP test");
});
3. run很多写法,用法不固定,我喜欢方法2,其他写法可自行百度。

注意:

        如果想在单独开启的线程中共享主函数的资源,要么使用 = ,然后传递指针,要么就是使用引用 & ,否则无法进入匿名表达式。

2.3 继承自QThread

只有run()函数里面,才是多线程,不推荐使用。还不如使用QtConcurrent::run()呢。

2.4 QRunnable

继承自QRunnable,然后使用下面这个启动:

Worker *work_0 = new Worker();
QThreadPool::globalInstance()->start(work_0);

简单易用,不过显然没有前面两种方便。

11. Windows的QT项目打包

+ release 模式,编译运行一次,然后把exe文件复制到其他目录下。

+ 根据自己的版本和编译模式搜索:官方自带的命令行工具(普通的CMD不行)

+ 使用QT自带的cmd,管理员 如 Qt 5.14.2 (MinGW 7.3.0 64-bit)
+ 然后 :     e:  进入到E盘
+ cd 路径     cd E:\QT_project\MyLovers1\result\
+ 执行:      windeployqt XX.exe

+ 然后把其他第三方库放进来,最后测试一下。

+ 如果需要,可以使用Enigma Virtual Box将整个文件打包为一个EXE程序。

12. 延时执行:

QThread::sleep()  和   Sleep()  可能导致主线程和其他线程的阻塞,造成卡顿
推荐延时使用:
QTimer::singleShot(2000, [=](){
    qDebug() << "Delayed execution after 2 seconds";
});

如果是子线程,不怕卡顿的话,可以使用QThread::sleep()
    
如果时间比较长,可能造成卡顿,可以使用这种方法:

// 创建一个事件循环对象
QEventLoop eventLoop;
QTimer::singleShot(2000, [&eventLoop](){
   qDebug() << "Delayed execution after 2 seconds";
   eventLoop.quit(); // 退出事件循环
});
// 进入事件循环并等待定时器触发
eventLoop.exec();

13. MSVC解决中文乱码

在pro文件中添加:

msvc {
    QMAKE_CFLAGS += /utf-8
    QMAKE_CXXFLAGS += /utf-8
}

14. 解决打开子窗口任务栏图标隐藏

但是为了防止关闭子窗口的时候,并没有合理的释放资源,先提前定义指针,只有点击按钮,才创建对象,关闭的时候,记得判断是否创建过:

void MainWindow::on_mainBtn_1_clicked()
{
    if(setting_win == nullptr){
        setting_win = new SettingUI(this);
        connect(setting_win,&SettingUI::closed,[=](){
            this->show();
        });
    }
    this->hide();
    setting_win->show();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    event->accept();
    if(exper_win!=nullptr){delete exper_win;exper_win->stopAllDev();}
    if(data_win!=nullptr)delete data_win;
    if(setting_win!=nullptr)delete setting_win;
    deleteLater();

}

15. linedit限制范围

#include <QIntValidator>
#include <QDoubleValidator>
#include <QIntValidator>

1.只允许输入整型
ui->lineEdit->setValidator(new QIntValidator(ui->lineEdit));

2.只允许输入数字
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("[0-9]+$")));  

2.1.只允许数字0-9且长度为11位
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("[0-9]{11}")));

3.只能输入字母和数字
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z0-9]+$"))); 

4.只能输入大写字母
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^[A-Z]+$")));

5.只能输入小写字母
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^[a-z]+$")));

6.只能输入字母
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^[A-Za-z]+$")));

7.输入浮点型数据
非负浮点数(正浮点数 + 0):"^\d+(\.\d+)?$"
正浮点数:"^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$"
非正浮点数(负浮点数 + 0):"^((-\d+(\.\d+)?)|(0+(\.0+)?))$"
负浮点数:"^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$" 
浮点数:"^(-?\d+)(\.\d+)?$"

8.输入-255~255的整数
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^-?(255|[1,2]?[0-4]?\\d|[1,2]?5[0-4]?)$"))); 

9.限制浮点数输入范围为[-90,90]并限定为小数位后4位
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp rx("^-?(90|[1-8]?\\d(\\.\\d{1,4})?)$")));

10.输入格式 (年-月-日)
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^(d{2}|d{4})-((0([1-9]{1}))|(1[1|2]))-(([0-2]([1-9]{1}))|(3[0|1]))$"))); 

10.1.输入格式(月/日/年)
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^((0([1-9]{1}))|(1[1|2]))/(([0-2]([1-9]{1}))|(3[0|1]))/(d{2}|d{4})$")));  

11.只能中文输入
ui->lineEdit->setValidator(new QRegExpValidator(QRegExp("[\u4e00-\u9fa5]+$")));  

// 限制范围:****************************************************************
ui->lineEdit_acqTime->setValidator(new QIntValidator(20, 2000,ui->lineEdit_acqTime));
ui->lineEdit_lineSwapTime->setValidator(new QDoubleValidator(0.03, 0.1,2,ui->lineEdit_lineSwapTime));

16. QT的pro:

# 新加入模块
QT       += core gui multimediawidgets


# 执行文件编译到 /bin目录中
DESTDIR = $$PWD/bin 


# 添加子模块,以MainCtlModule为例,需要新建MainCtlModule文件夹,以及内部的MainCtlModule.pri文件
INCLUDEPATH += $$PWD/MainCtlModule
include($$PWD/MainCtlModule/MainCtlModule.pri)


# 获取系统架构信息,根据系统指定环境
system_arch = $$system(uname -m)
equals(system_arch, "x86_64") {
    message("x86_64 架构")
    # 虚拟机环境:************************
    CONFIG += link_pkgconfig
    PKGCONFIG += gstreamer-1.0 gstreamer-plugins-base-1.0 #gtk+-3.0
    LIBS += -lX11
    LIBS    +=-lglib-2.0
    LIBS    +=-lgobject-2.0
    LIBS    +=-lgstreamer-1.0          # <gst/gst.h>
    LIBS    +=-lgstvideo-1.0             # <gst/video/videooverlay.h>
    LIBS    +=-L/usr/lib/x86_64-linux-gnu/gstreamer-1.0
    #LIBS    +=-lgstautodetect
    LIBS    +=-lgstaudio-1.0
    LIBS    +=-lgstapp-1.0
    LIBS    += -L/usr/local/lib/ -lgstrtspserver-1.0

    INCLUDEPATH += \
                /usr/include/glib-2.0 \
                /usr/lib/x86_64-linux-gnu/glib-2.0/include \
                /usr/include/gstreamer-1.0 \
                /usr/lib/x86_64-linux-gnu/gstreamer-1.0/include

}else:equals(system_arch, "aarch64") {
    message("aarch64 架构")



}else {
    error("不支持的架构: $$system_arch")

}

三、其他

1. Windows好用工具记录:

  • utools                非常方便的插件合集
  • pixpin                新晋截图神器
  • cmder                好用的命令行工具,可以在Windows电脑,像Linux那些命令来操作
  • Snipaste            之前的截图神器
  • Win + Shift + S  自由截图
  • Everything         文件搜索神器
  • notePad++        好用的TXT编辑器
  • MobaXterm       联调神器,可以链接串口、SSH、FTP、VNC。。。很多设备
  • Bandicam          好用的录屏软件
  • typora                请下载旧版,makedown神器
  • GifCam              好用的GIF动图截图工具
  • iperf                   测带宽和网速
  • Navicat              多种数据库连接
  • VLC                   超好用的视频播放和音视频开发播放器
  • OBS                   免费的录屏和直播软件
  • sscom                超好用的串口和网络调试工具
  • Enigma Virtual Box   封装工具
  • 向日葵                远程桌面
  • 亿图                    好用的画图工具,各种工程图和导图等等,还有丰富的素材
  • Iris_Pro               护眼软件
  • vspd                    虚拟串口工具
  • HEU_KMS_Activator    window和office激活
  • npcap                  扫描工具,网安和黑客常用
  • Wireshark            抓包工具
  • VMware               虚拟机
  • 网易有道翻译       截图翻译
  • 小熊猫dev            学习C++入门的IDE神器,适合学生
  • drow.io                 免费好用的绘图软件,平替vioso
  • 躺平设计家           装修设计软件,3D,免费

2. Linux好用工具记录

  • FileZilla                Linux中文件传输
  • iftop                      查看网卡、IP、端口的流量
  • tcpdump               类似libpcap,可以查看指定IP和端口流量,可以抓包保存文件
  • gitg                       图形化git工具
  • Goolge Chrome    谷歌浏览器
  • Onboard               虚拟键盘
  • ffmpeg                   音视频框架和工具
  • gstreamer              音视频框架和工具
  • wireshark               抓包神器
  • VLC                       播放器神器
  • Vim                        编辑神器
  • Typora                   markdown神器,不过要下载旧版
  • iperf3                     生成网络数据,可用于测试网速
  • v4l-utils                  查看相机参数的工具
  • v4l2loopback-utils  虚拟相机
  • iproute2 和 net-tools   网络工具
  • linux-image-()         通过uname -r查看,安装某个版本的内核
  • docker                     容器
  • remmina-common   远程桌面,支持VNC
  • qt 
  • anaconda                好用的python环境,比如jupyter notebook
  • nginx-extras            nginx服务器
  • expect                     expect脚本

3. C++开发框架或者库

  • ffmpeg                  音视频开发框架1
  • gstreamer             音视频开发框架2
  • NGINX                  web常用的工具
  • OpenGL                渲染
  • OpenCV                图片和视频处理,还有AI识别
  • libssh                     ssh
  • libpcap                   抓包

待补充...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿龍1787

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值