
C++
文章平均质量分 53
休息一下接着来
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
C++ call_once用法
📌 摘要 std::call_once 是 C++11 提供的线程安全单次调用工具,用于确保函数在多线程环境中仅执行一次,适用于单例模式、延迟初始化等场景。 🔹 核心机制 配合 std::once_flag 标志位跟踪执行状态。 首次调用时执行目标函数,后续调用自动跳过。 若函数抛出异常,允许其他线程重试。 ⚡ 优势 无需手动加锁,内置线程安全。 支持异常处理与延迟初始化。 ⚠️ 注意 once_flag 不可复制/移动,需全局或静态管理。 初始化函数应避免长时间阻塞。 📝 示例 // 线程安全单例原创 2025-06-11 17:25:53 · 385 阅读 · 0 评论 -
进程间通信(IPC): POSIX 消息队列
POSIX 消息队列是进程间通信(IPC)的一种机制,允许进程通过内核管理的队列发送和接收离散消息,适合本地异步通信。消息队列由用户定义的名称(如 `/myqueue`)标识,内核维护消息的存储和传递。原创 2025-05-20 11:20:06 · 886 阅读 · 0 评论 -
进程间通信(IPC):LocalSocket
LocalSocket 是基于 Unix 域套接字(Unix Domain Socket)的 IPC 机制,用于同一设备上的进程间通信。它通过内核直接传递数据,绕过网络协议栈,具有高效率和低延迟的特点,广泛应用于 Android 系统(如与 Zygote 通信)或本地服务通信。原创 2025-05-20 09:23:44 · 1124 阅读 · 2 评论 -
进程间通信(IPC)常用方式对比
进程间通信(IPC)是操作系统中不同进程之间交换数据的机制,广泛用于多进程应用(如客户端-服务器模型、系统服务通信)。以下对比五种常见 IPC 方式:LocalSocket(Unix 域套接字)、管道、消息队列、共享内存和信号。原创 2025-05-20 09:17:25 · 1071 阅读 · 0 评论 -
C++ I/O多路复用
I/O多路复用是一种允许程序同时监视多个文件描述符(如套接字、文件等)的技术,检查它们是否准备好进行读、写或异常操作,而无需为每个描述符创建单独的线程或进程。这种技术在网络编程和高并发应用中至关重要,主要优点包括高效性、资源节约、可扩展性和简化设计。常见的I/O多路复用机制包括select、poll、epoll(Linux特有)和kqueue(BSD/macOS特有)。select和poll适合跨平台和小规模场景,而epoll和kqueue则在高并发环境下表现优异。选择合适的多路复用机制应根据项目需求和平台原创 2025-05-16 16:45:44 · 793 阅读 · 0 评论 -
C++ 双缓冲区生产者-消费者
双缓冲区(Double Buffering)是一种用于优化多线程或并发环境中数据生产和消费性能的技术。它通过使用两个缓冲区(前缓冲区和后缓冲区)来减少线程间的竞争和锁的使用,从而提高吞吐量。核心思想是生产者向写缓冲区写入数据,消费者从读缓冲区读取数据,当写缓冲区满或读缓冲区空时,交换两个缓冲区。双缓冲区的优点包括减少锁竞争、提高效率和适用于实时数据处理等场景,但也存在内存使用增加和实现复杂度较高的缺点。在C++中,双缓冲区可以通过互斥锁和条件变量实现线程安全,并通过交换缓冲区来协调生产者和消费者的操作。双缓原创 2025-05-16 15:06:01 · 826 阅读 · 0 评论 -
C++ 条件变量与线程通知机制:std::condition_variable
std::condition_variable 是 C++11 引入的线程间通信机制,通常与 std::mutex 配合使用,适用于生产者-消费者模型等场景。其核心原理是通过 wait() 使线程进入阻塞状态,直到其他线程调用 notify_one() 或 notify_all() 唤醒它。wait() 会自动释放并重新获取锁。需要注意的是,wait() 可能发生虚假唤醒,即线程在没有收到通知时被唤醒,因此推荐使用带谓词版本的 wait(lock, predicate),确保线程仅在条件满足时继续执行。示例原创 2025-05-16 14:51:44 · 588 阅读 · 0 评论 -
C++ 中的几种锁机制整理
本文介绍了四种常见的线程同步工具:互斥锁、自旋锁、读写锁和原子锁。互斥锁(std::mutex)是最常用的同步工具,简单易用,但锁竞争时线程会挂起,涉及上下文切换。自旋锁通过忙等待方式避免线程切换,适合临界区执行时间极短的场景,但会占用CPU资源。读写锁(std::shared_mutex)允许多个线程并发读,写操作独占,适合读多写少的场景。原子锁(基于std::atomic)利用原子变量实现无锁同步,性能极高,但仅适用于简单场景。总结对比了四种锁的阻塞性、性能、适用场景及标准库支持情况,帮助开发者根据具体原创 2025-05-16 14:24:35 · 442 阅读 · 0 评论 -
Linux动态库热加载驱动插件机制-示例
本文介绍了一种插件式驱动系统的设计与实现,旨在通过动态加载外部 .so 驱动,使主程序能够灵活调用不同功能。系统核心基于工厂模式,利用 dlopen() 加载插件,并通过静态对象构造自动注册驱动到单例工厂。插件结构包括驱动接口基类、工厂注册类模板和插件注册辅助模板,支持 C++ 标准类型和继承体系。主程序通过工厂单例获取驱动实例并调用接口,无需手动注册或暴露 C 符号。该设计简洁高效,符合现代 C++ 插件开发理念,适用于需要动态扩展功能的场景。原创 2025-05-15 16:26:33 · 354 阅读 · 0 评论 -
Linux 动态库热加载
热加载(Hot Reload)是一种在不重启主程序的情况下,通过动态加载或重新加载动态库(.so 文件)来更新或替换逻辑的技术。其核心流程包括使用 dlopen 加载库、dlsym 获取函数地址、dlclose 卸载库等系统函数。为了确保 dlsym 能正确识别函数名,建议使用 extern "C" 避免 C++ 的名称修饰。动态库函数的参数设计应尽量使用简单类型(如 int、const char*、void*),避免使用 C++ 标准库类型(如 std::string、std::vec原创 2025-05-15 14:20:56 · 273 阅读 · 0 评论 -
C++ 中的最大值和最小值判断
是 C++ 标准库中的模板类,用于获取各种数据类型的最大值和最小值。它提供了一种通用的方式,适用于所有标准数据类型(如intlongfloatdouble等)。原创 2025-01-21 21:38:19 · 394 阅读 · 0 评论 -
查找子串方法总结
是 C++ 标准库中的一个算法,属于泛型编程的范畴。它能够在容器的任意范围内查找子序列。泛型编程的核心思想是编写代码,使其能够处理不同类型的容器和迭代器,而不依赖于具体的容器实现。是由标准库实现的,经过了优化,性能较好。实测效率高,推荐使用。原创 2024-07-15 18:04:43 · 1063 阅读 · 0 评论 -
C++ 锁管理:std::lock_guard 和 std::unique_lock 使用方法
适用于简单的自动化锁定和解锁场景,功能有限但性能开销小。:适用于需要更复杂控制的场景,例如手动解锁、重新加锁及与条件变量配合使用,提供了更多的灵活性,但性能开销较大。原创 2024-07-05 17:09:46 · 1251 阅读 · 0 评论 -
使用sstream库处理字符串流
sstream提供了一系列类,用于字符串流操作。下面是如何使用这些类的一些示例。原创 2024-06-28 11:13:48 · 276 阅读 · 0 评论 -
C++ 左值和右值
C++中左值(lvalue)和右值(rvalue)是比较基础的概念,虽然平常几乎用不到,但C++11之后变得十分重要,它是理解 move/forward 等新语义的基础。左值和右值主要的区别之一是左值可以被修改,而右值不能。左值与右值这两个概念是从 C 中传承而来的。左值指既能够出现在等号左边,也能出现在等号右边的变量;右值则是只能出现在等号右边的变量。2. 左值引用和右值引用左值引用:引用一个对象;右值引用:就是必须绑定到右值的引用,C++11中右值引用可以实现“移动语义”,通过 && 获得右值引转载 2022-06-14 10:38:36 · 1058 阅读 · 0 评论 -
C++ 拷贝控制(五):阻止拷贝
有些类应该阻止拷贝,比如iostream类阻止了拷贝,以避免多个对象写入或者读取相同的IO缓存。如果我们不定义拷贝控制成员,但是编译器会默认为我们定义这些操作,因此不能阻止类的拷贝。通常阻止拷贝主要有定义删除函数和private拷贝控制两种方法。我们可以通过将拷贝构造函数和赋值拷贝运算符定义为删除函数来阻止拷贝。删除函数是一种函数,虽然我们定义了它们,但是不能以任何方式使用它们。特别注意:由于析构函数是public的,用户可以定义NoCopy类型的对象。但是由于拷贝构造函数和拷贝赋值运算符是privat原创 2022-06-09 15:33:50 · 2402 阅读 · 2 评论 -
C++ 拷贝控制(四):使用=default
可以通过将拷贝控制成员定义为 =default 来显示地要求编译器生成合成版本。特别注意:在类内使用=default修饰成员的声明时,合成的函数将隐式地声明为内联的(就像任何其他类内声明的成员函数一样)。如果不希望合成的成员时内联函数,应该只对成员的类外定义使用=default,就像上面拷贝赋值运算符随做的那样。...原创 2022-06-08 18:54:20 · 461 阅读 · 0 评论 -
C++ 拷贝控制(三):析构函数
析构函数执行与构造函数相反的操作:构造函数初始化对象的非static数据成员,还可能做一些其他的工作。析构函数释放对象使用的资源,并销毁非static数据成员。在一个析构函数中,不存在类似构造函数中,初始化列表的东西。来控制成员如何销毁,析构部分是隐式的。成员销毁时发生什么完全依赖于成员的类型。销毁的成员需要调用自己的析构函数销毁。内置类型没有析构函数,销毁内置类型什么也不需要做。注意:隐式销毁一个内置指针类型的成员不会delete它所指的对象。与普通指针不同,智能指针是类类型的,具有析构函数。智能指针成原创 2022-06-08 16:47:11 · 324 阅读 · 0 评论 -
C++ 拷贝控制(二):拷贝赋值运算符
与类控制其对象如何初始化一样,类也可以控制对象如何赋值:1. 重载赋值运算符重载运算符本质上是一个函数,由operator关键字后接要定义的运算符的符号组成。赋值运算符是由一个名为"operator="的函数。类似于其他任何函数,运算符函数也有一个返回类型和参数列表。为了与内置类型的赋值保持一致,赋值运算符通常返回一个指向其左侧运算对象的引用。标准库通常要求保存在容器中的类型要具有赋值运算符,且其返回值是左侧运算对象的引用与处理拷贝构造函数一样,如果一个未定义自己的拷贝赋值运算符,编译器会为它生成一个原创 2022-06-07 17:28:51 · 472 阅读 · 0 评论 -
C++ 拷贝控制(一):拷贝构造函数
拷贝控制,当定义一个类时,我们显式或隐式地指定在此类型的对象拷贝、移动、赋值和销毁时做什么。通过一下五种特殊的成员函数来控制这些操作:拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符、析构函数。如果我们没有定义这些拷贝控制成员,编译器会自动定义确实操作。因此很多类,忽略了这些拷贝控制操作。但是,有些类依赖这些操作默认的定义会导致意想不到的灾难。.........原创 2022-06-07 15:53:19 · 223 阅读 · 0 评论 -
C++ 内存分配(静态内存、栈和堆)
内存分为三种:静态内存、栈内存和堆内存1. 静态内存静态内存用来保存局部static对象、类的static数据成员、以及定义在任何函数之外的变量。保存对象:局部static对象void func(){ static int a; // 局部static对象}类的static数据成员class Function(){public: static void func(); // 类中static函数private: static int i_func; /转载 2022-04-27 18:03:20 · 1382 阅读 · 1 评论 -
C++ 字符串的截取
按照字符串截取/** * @brief 按照指定的字符串截取字符串 * @param str 需要截取的字符串 * @param pattern 按照该字符串截取 * @return 截取好的字符串vector */std::vector<std::string> splitStr(std::string str, std::string pattern){ std::string::size_type pos; std::vector<std.原创 2022-04-20 17:12:50 · 10909 阅读 · 1 评论 -
C++ 字节流指针(字符数组)与string类型的转换
字符数组换成string// 定义一个字符数组char a[4] = "asd";// 将字符数组换成字符串string result = string(a, a + sizeof(a));String转换成字符数组// 定义一个字符串string a = "asd";// 将String转换成字符数组char *result = const_cast<char*>(a.c_str());int length = a.size();...原创 2022-04-20 16:42:46 · 2390 阅读 · 0 评论 -
大小端及转换(C++)
1. 基本概念大小端表示数据在存储器中存放的顺序。大端模式: 数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;小端模式:数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。假如在一段内存中存储如下数据uint8_t A = 0xA1;uint8_t原创 2022-03-03 17:40:36 · 14158 阅读 · 0 评论 -
C++ string转换int型
使用sscanf()函数#include <iostream>int main(){ std::string test = "1,2,3,4"; int a , b; sscanf(test.c_str(), "%d,%d", &a,&b); std::cout <<"a: " << a << std::endl; std::cout <<"b: " << b <.原创 2022-02-08 15:43:21 · 777 阅读 · 0 评论 -
C++ 再探智能指针(三):weak_ptr
基础概念阅读另一篇文章:C++ 智能指针 : https://blog.csdn.net/qq_28256407/article/details/119377508weak_ptr是一种不控制所指向对象生存周期的智能指针,它指向由一个shared_ptr管理的对象。将一个weak_ptr绑定到一个shared_ptr的对象不会改变其引用计数。当shared_ptr被销毁,即使有weak_ptr指向对象,对象还是会被释放。weak_ptr支持的操作weak_ptr<T> w /原创 2021-11-04 17:00:29 · 898 阅读 · 0 评论 -
C++ 再探智能指针(二):unique_ptr
基础概念阅读另一篇文章:C++ 智能指针 : https://blog.csdn.net/qq_28256407/article/details/119377508unique_ptr支持的操作p // 将p当做一个条件判断,若p指向一个对象则为true*p // 解引用p,获得指向它的对象、p->mem // 等价于 (*p).mem 访问成员p.get() // 返回p中保存的指针(指向对象的普通指针)。如果智能指针释放了其对象,返回的指针也会被释放swap(p原创 2021-11-03 21:49:19 · 328 阅读 · 0 评论 -
C++ 再探智能指针(一):shared_ptr
【基础参考】C++ 智能指针: https://blog.csdn.net/qq_28256407/article/details/119377508shared_ptr支持的操作p // 将p当做一个条件判断,若p指向一个对象则为true*p // 解引用p,获得指向它的对象、p->mem // 等价于 (*p).mem 访问成员p.get() // 返回p中保存的指针(指向对象的普通指针)。如果智能指针释放了其对象,返回的指针也会被释放swap(p, q) //原创 2021-11-02 23:38:02 · 348 阅读 · 0 评论 -
C++ std::cout 打印不出来uint8_t 和 int8_t
今天在测试程序时发现,发现一直打印不出某些数据,检查了好多遍,没有发现问题。经过多次测试,发现凡是uint8_t和int8_t的数据,都无法用std::cout打印出来。随后写个小程序测试了一下,发现确实如此。查过资料才明白,其中的原因。不得不说是个好坑。。。#include<iostream>int main(){ uint8_t a = 10; int8_t b = 5; std::cout << "uint8_t a: " << a &原创 2021-10-27 23:30:42 · 7902 阅读 · 4 评论 -
C++ std::vector删除元素的几种方式及区别
容器vector在删除过程中,常用的函数。函数作用pop_back()删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量(capacity)不会发生改变。erase(iter)删除 vector 容器中iter迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。erase(iter1,iter2)删除 vector 容器中位于迭代器 [iter1,i原创 2021-10-24 23:19:30 · 42542 阅读 · 0 评论 -
C++ std::vector: vector中元素的存储方式 size、capacity、reserve、resize的使用
1. vector的对象的存储方式为了支持随机访问,vector将元素连续存储–每个元素紧挨着前一个元素存储。容器中元素是连续存储的,且容器的大小是可变的。在容器中增加元素时。vector根据存储元素的大小,在内存上申请一个空间,用于存储数据,空间的大小通常会大于所存储元素的实际大小,并且预留出一部分预留的空间,以便再次增加数据时,可以不用重新开辟空间。当容器再次增加新的元素后,首先判断预留的空间是否够用,如果够用直接在预留空间中存储。如果预留的空间不够,需要在内存中开辟一整块新的更大的空间,并将ve原创 2021-10-24 10:54:45 · 3028 阅读 · 0 评论 -
C++类: 类中的静态成员
类的静态成员与类本身直接相关,而不是类的各个对象保持关联1. 声明静态成员在成员声明之前,加上static关键字,使其与类的成员关联在一起。静态成员可以是public或者private的。惊天数据成员的类型可以使用常量、引用、指针、类类型等。#include <iostream>struct test{public: static int a; // 定义静态成员 static char b; // 定义静态成员public: static int m原创 2021-09-15 17:44:28 · 615 阅读 · 0 评论 -
C++类: 聚合类
1. 聚合类的基本概念聚合类使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。当一个类满足如下条件时,我们说他是聚合的:所有成员都是public的。没有定义任何构造函数。没有任何类内初始值。没有基类,也没有virtual函数如:struct test{ int a; string b;};2. 聚合类赋初值的基本方法struct test{ int a; string b;};test x = {1, "hello world"};原创 2021-09-15 12:20:38 · 1075 阅读 · 0 评论 -
C++类: 构造函数隐式转换及explicit关键字
1. 构造函数的隐式转换C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色。构造;默认且隐含的类型转换操作符。#include <iostream>struct test{public: test(bool ii) {};};int main(){ test x = 1; // 隐式转换构造,拷贝初始化 test y(2); // 直接赋值构造}2.抑制构造函数的隐式原创 2021-09-15 11:02:45 · 448 阅读 · 0 评论 -
C++ 类:构造函数(2)
1. 构造函数初始值列表初始化与构造函数内赋值class test{public: test() { a = 10; // 构造函数内赋值(实际上在调用函数时,已经对a进行了初始化为0,此处是再次进行赋值) }public: int a;};class test{public: test() : a(10) {} // 利用构造函数列表进行初始化public: int a;};注意:虽然上述两种法效果相同:当构原创 2021-09-14 16:53:34 · 132 阅读 · 0 评论 -
C++ 类:访问控制与封装
1. 访问说明符在c++中,使用访问说明符加强类的封装性。public:定义在public说明符之后的成员在整个程序内被访问,public定义类的接口。private:定义在private说明符之后的成员可以被类的成员函数访问,但是不是被使用该类的代码访问,private部分封装了(隐藏了)类的实现细节。注意:一个类可以包含任意个访问说明符,对某个说明符出现的次数也没有限制。每个访问符说明了接下来成员访问的级别,其有效范围直到出现下一个访问说明符或者到达类的结尾处为止。2.clsss和stru原创 2021-09-12 12:13:58 · 169 阅读 · 0 评论 -
C++ 类:构造函数(1)
1. 构造函数的基本概念每个类都分别定义了他的对象被初始化的方式。类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。构造函数的名字和类的名字相同构造函数没有返回类型构造类型可以有多个,满足函数重载的规则2.合成的默认构造函数如果在类中没有定义任何构造函数,编译器会隐式的创建一个特殊的构造函数,来控制默认初始化的过程,这个函数叫做默认构造函数。初始化类的数据成员时:如果存在类内原创 2021-09-09 16:22:35 · 265 阅读 · 1 评论 -
C++函数: 函数指针
函数指针指向的是函数而非对象。和其他指针类型一样,函数指针指向某种特定的类型。函数的类型由它的返回类型和形参共同决定,与函数名无关。// 比较两个string对象长度bool lengthCompare(const string &, const string &);// pf指向一个函数,函数的参数是两个const string的引用,返回值是bool型bool (*p)(const string &, const string &); // 未初始化注意:原创 2021-09-08 22:27:04 · 198 阅读 · 0 评论 -
C++函数: 函数的返回值为引用或指针
1. 函数的返回值为引用如果函数的返回值为引用,则不需要创建无名临时对象,避免构造函数和析构函数的调用,从空间和时间上提高了程序执行的效率。例子:#include <iostream>#include <string>using namespace std;string& Test(string &temp_str) // 定义函数的返回值为引用类型{ return temp_str;}int main(){ string test("H原创 2021-09-08 18:03:00 · 3818 阅读 · 0 评论 -
C++工程调试的帮助:预处理功能 assert 和 NDEBUG
程序包含用于调试部分的代码,这部分代码只在开发程序时使用。当应用程序发布时,屏蔽掉调试代码。这种方法用到两项预处理功能:assert 和 NDEBUG。1. assert预处理宏assert是一种预处理宏,其实是一个预处理变量,其行为类似于内联函数。表达式assert(expr); // 首先对expr求值,如果表达式为假(0),assert输出信息,并终止程序执行// 如果表达式为真(非0),assert啥也不做注意:assert宏定义在头文件中,宏定义的名字由预处理器处理,而不是编原创 2021-09-08 18:00:40 · 1214 阅读 · 0 评论