yoola's Blog - C++
type: channel
link: https://yoola.top/tag/C
items: 牛逼了，C++哈希表(std::unordered_map<type1, type2>)
items: Makefile异常处理-"C++: error: exception handling disabled, use -fexceptions to enable"
items: [强化记忆]C++类枚举的使用
items: 基于VSCode和CMake进行C/C++开发的LInux平台环境配置
items: C++遍历windows文件夹
items: C++模板类LNK2019 错误：“ 无法解析的外部符号 ” 详解
items: C++11回调函数与注意事项
items: C++STL—常用算法
items: C++STL内建函数
items: C++谓词

牛逼了，C++哈希表(std::unordered_map<type1, type2>)
type: item
date: 2023-08-09T13:21:00+08:00
description: 1. 哈希表是什么哈希表（Hash table），也称散列表，是根据关键码的值而直接进行访问的数据结构。C++名字unordered_map或unordered_set，Set与Map一个是只有Value，另一个带Key。(Map,键值对)哈希表的增删改查的时间复杂度都是常数级，使用时特别高效。时间复杂度为o(1)，空间复杂度为o(n)。2. 哈希函数就是根据哈希key按照一定逻辑求出哈希value。3. 哈希碰撞多个value绑定到了同一个哈希key下面,当访问的时候，得到的vlaue不唯一。4. 哈希冲突的解决方法开放定址法线性探测法二次探测法随机探测法再散列函数法事先准备多个散列函数公共溢出区法建立两张表，一张为基本表，另一张为溢出表。链地址法（拉链法）冲突的数据全部存储在同一个线性链表中。5.常见的三种哈希结构1.数组2.set （集合） 集合 底层实现 是否有序 数值能否重复 数值能否更改 增删改查效率 std::set 红黑树 有序 否 否 O(logn) std::multiset 红黑树 有序 是 否 O(logn) std::unordered_set 哈希表 无序 否 否 O(1) 3.map（映射） 映射 底层实现 是否有序 key能否重复 key能否更改 增删改查效率 std::map 红黑树 有序 否 否 O(logn) std::multimap 红黑树 有序 是 否 O(logn) std::unordered_map 哈希表 无序 否 否 O(1) 6.添加数据std::unordered_map<std::string,std::vector<std::string>> unrdered_strings; std::string MyStr("123"); std::string TheStr("I LOVE YOU !"); unrdered_strings[MyStr].emplace_back(TheStr);

Makefile异常处理-"C++: error: exception handling disabled, use -fexceptions to enable"
type: item
date: 2023-01-08T00:40:00+08:00
description: Makefile异常处理：C++: error: exception handling disabled, use -fexceptions to enable原因分析这是因为你的工程中使用了C++的异常处理机制（try-throw），而编译器不推荐这种操作，所以默认不开启，需要手动在Makefile文件里添加。解决方法在Makefile文件中添加-fexceptions参数即可，添加在生成.o文件时例子# Makefile rules... .c.o : $(OBJECTS.C) $(CC) -I. $(CFLAGS) $(INCLUDES) $(MMAL_CFLAGS) -D__MMAL_ENCODER_DEBUG__ -c $< -o $@ .cc.o : $(OBJECTS.CC) $(CXX) -I. $(CFLAGS) $(CCFLAGS) $(MMAL_CFLAGS) $(INCLUDES) -c $< -o $@ -fexceptions -fpermissive # 增加 -fexceptions -fpermissive 参数，以使用MQTTCPP库的throw $(TARGET): $(OBJECTS) $(CXX) $(LDFLAGS) -o $(TARGET) -Wl,--start-group $(OBJECTS) $(BUILD_LIBS) -Wl,--end-group $(SYSLIBS) -lwiringPi -lbcm2835 -lpaho-mqttpp3 -lpaho-mqtt3a

[强化记忆]C++类枚举的使用
type: item
date: 2023-01-07T17:37:00+08:00
description: C++类枚举的使用1 单独类枚举使用方法#include <iostream> enum class MyEnum ：unsigned char //冒号后是指定枚举数据类型为 unsigned char { one = 1,two,three }; int main() { std::cout << MyEnum::one << std::endl; }2 类内枚举使用方法#include <iostream> class MyClass { public: enum MyEnum {one = 0, two, three}; }; int main() { std::cout << MyClass::one << std::endl; }3 类枚举变量声明及使用#include <iostream> class MyClass { public: enum MyEnum {one = 0, two, three}; }; int main() { MyClass::MyEnum EENUM; EENUM = MyClass::one; //auto EENUM = MyClass::one;//可以使用自动类型 std::cout << EENUM << std::endl; }4 类枚举错误荟萃4.1 类枚举成员重复#include <iostream> class MyClass { public: enum MyEnum {one = 1, two, three}; enum MyEnum_1 {one = 1}; //错误，因为在类内one这个枚举元素是唯一的，已经在上一句中定义了 }; int main() { MyClass::MyEnum EENUM; EENUM = MyClass::one; std::cout << EENUM << std::endl; }4.2 类枚举变量赋值中，枚举名与枚举元素不对应#include <iostream> class MyClass { public: enum MyEnum {one = 1, two, three}; enum MyEnum_1 {four= 4}; }; int main() { MyClass::MyEnum EENUM; EENUM = MyClass::four; //错误，因为MyClass::four不是MyClass::MyEnum枚举名的成员，是MyClass::MyEnum_1 的 std::cout << EENUM << std::endl; }

基于VSCode和CMake进行C/C++开发的LInux平台环境配置
type: item
date: 2023-01-03T23:57:00+08:00
description: 基于VSCode和CMake进行C/C++开发的LInux平台环境配置Make与Makefile的关系make是个命令工具，解释Makefile中的指令，在make文件中描述了整个工程所有文件的编译顺序、编译规则Cmake是啥Cmake是一个跨平台的安装(编译)工具，可以用简单的语句来描述所有平台的安装(编译过程)。能够输出各种makefile或者project文件，能测试编译器所有支持的C++特性。Cmake的组态栏取名为CMakeLists.txt。Cmake并不直接构建出最终的软件，而是产生标准的构建档，然后再依照一般的构建方式使用。Cmake与CMakeLists的关系cmake是一个命令工具，可以用来生成makefile。但是也要根据CmakeLists.txt中的内容来生成,CMakeLists.txt就是写给cmake的规则。重点make是一个命令工具，Makefile是一个文件，make执行的时候，去读取Makefile文件中的规则，重点是makefile文件得自己写。cmake是个命令工具，CMakeLists.txt是一个文件,cmake执行的时候，去读取CMakeLists.txt文件中的规则，重点是CMakeLists.txt得自己写。一、开发环境搭建安装GCC,GDBsudo apt-get install build-essential gdb #安装成功确认 gcc --version g++ --version gdb --version安装CMakesudo apt-get install cmake #安装成功确认 cmake --version二 、GCC编译器-MakeFile文件目标文件:依赖文件 [tab] 指令 #先写输出后写输入，一步步递进 #伪目标 .PHONY: #rm -rf hello.o hello.S hello.i hello:hello.o gcc hello.o -o hello hello.o:hello.S gcc -c hello.S -o hello.o hello.S:hello.i gcc -S hello.i -o hello.S hello.i:hello.c gcc -E hello.c -o hello.i .PHONY:#伪目标 clear:#这是个操作名字 使用 make clear可以执行以下指令 rm -rf hello.o hello.S hello.i完事以后使用make指令即可伪目标(.PHONY:).PHONY:#伪目标 clear:#这是个操作名字 使用 make clear可以执行以下指令 rm -rf hello.o hello.S hello.i多文件#文件列表为 src.c src.h main.c main.h #可执行文件取名为output output:src.o main.o gcc src.o mian.o -o output src.o:src.c gcc -c src.c -o src.o main.o:main.c gcc -c mian.c -o main.o .PHONY: clearall:#这是个操作名字 使用make clearall 可以执行以下指令 rm -rf src.o main.o output变量(替换、追加、恒等于、使用)变量替换=、变量追加+=、常量恒等于:=、使用变量$(变量)#文件列表为 src.c src.h main.c main.h #可执行文件取名为test001 TAR = test #此时TAR为变量、可追加和改变 TAR += 001 #追加001 此时TAR = test001 CC := gcc #此时CC为常量、不可追加、不可改变 OBJ = src.o main.o #变量使用方法 $(TAR):$(OBJ) $(CC) $(OBJ) -o $(TAR) src.o:src.c $(CC) -c src.c -o src.o main.o:main.c $(CC) -c mian.c -o main.o .PHONY: clearall:#这是个操作名字 使用make clearall 可以执行以下指令 rm -rf src.o main.o output隐含规则(任意文件和所有文件)任意%.c、%.o所有*.c、*.o#文件列表为 src.c src.h main.c main.h #可执行文件取名为output TAR = output #此时TAR为变量、可追加和改变 #TAR += 001 #追加001 此时TAR = test001 CC := gcc #此时CC为常量、不可追加、不可改变 OBJ = src.o main.o #变量使用方…

C++遍历windows文件夹
type: item
date: 2022-07-29T11:14:00+08:00
description: 算法一：使用 _finddata_t#include <io.H> #include <string> #include <deque> //注意，本算法使用filter（fileType）只能遍历目标文件夹folderPath下的对应类型文件 void dfsFolder(std::string folderPath, std::deque<std::string> & filenames, std::string fileType = "") { _finddata_t FileInfo; if (*folderPath.rbegin() != '\\')//检查原始文件夹名称是否以'\\'结尾 { folderPath += "\\"; } if (fileType == "")//如果filter不启用 { fileType = "*.*"; } else if (fileType == "*.*" || fileType == "*")//无需操作、主要在回调本函数时使用 { } else { fileType = "*." + fileType; } std::string fileFindPath = folderPath + fileType; std::cout << "当前的查找目录为" << fileFindPath << std::endl; long Handle = _findfirst(fileFindPath.c_str(), &FileInfo); if (Handle == -1L) { std::cerr << "can not match the folder path" << std::endl; //exit(-1); return ; } do { //判断是否有子目录 if (FileInfo.attrib & _A_SUBDIR) { //这个语句很重要 if ((strcmp(FileInfo.name, ".") != 0) && (strcmp(FileInfo.name, "..") != 0)) { std::string newPath = folderPath + FileInfo.name; dfsFolder(newPath, filenames, fileType); } } else { std::string newPath = folderPath + FileInfo.name; filenames.push_back(newPath); std::cout << newPath.c_str() << std::endl; } } while (_findnext(Handle, &FileInfo) == 0); _findclose(Handle); } int main() { std::deque<string> ddd; dfsFolder("D:", ddd, "jpg");// system("pause"); return 0; }算法二：使用 _finddata_t#include <io.H> #include <string> #include <deque> //可遍历出子文件里的对应文件，可用filter进行文件后缀的过滤 int listAllFile(std::string path, std::deque<std::string> & dstFilePathList, std::string fileTypeFilter = "") { _finddata_t FileInfo; bool needFilter = false; std::string fileFindPath; if (*path.rbegin() != '\\') { path += "\\"; } else { } fileFindPath = path + "*.*"; if (fileTypeFilter == "" || fileTypeFilter == "*.*" || fileTypeFilter == "*") { needFilter = false; } else { needFilter = true; } std::cout << "当前的查找目录为" << fileFindPath << std::endl; long Handle = _findfirst(fileFindPath.c_str(), &FileInfo); if (Handle == -1L) { std::cerr << "can not match the folder path" << std::endl; //exit(-1); return -…

C++模板类LNK2019 错误：“ 无法解析的外部符号 ” 详解
type: item
date: 2022-06-01T12:56:00+08:00
description: 解决方法首先将出现这个错误应该怎么处理的方法写出来，解一些急着知道结果的攻城狮们燃眉之急：1.在主函数包含头文件时将实现模板类的函数也包含进来，如模板类在function1.cpp中实现，则在主函数中添加 #include "function.cpp"2.将模板类的实现方法写在头文件里面，如模板类的头文件为：function1.h，那么就把实现要用到模板类的函数实现方法写在这 里3.在实现模板类的文件中调用一下模板类————————————————版权声明：本文为CSDN博主「性感博主在线瞎搞」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。原文链接：https://blog.csdn.net/qq_41884002/article/details/99816073

C++11回调函数与注意事项
type: item
date: 2022-05-30T08:39:00+08:00
description: C++11回调函数与注意事项回调函数就是一个通过函数指针调用的函数。如果你把函数的指针（地址）作为参数传递给另一个函数，当这个指针被用来调用其所指向的函数时，我们就说这是回调函数。回调函数不是由该函数的实现方直接调用，而是在特定的事件或条件发生时由另外的一方调用的，用于对该事件或条件进行响应。回调函数可以是静态类函数也可以是全局函数。回调函数机制：定义一个函数（普通函数即可）；将此函数的地址注册给调用者；特定的事件或条件发生时，调用者使用函数指针调用回调函数注意事项全局函数可以直接作为回调函数C++将类函数直接作为回调函数，必须是静态函数原因：大概原因是普通的C++成员函数都隐含了一个传递函数作为参数，即this指针，C++通过传递this指针给成员函数从而实现函数可以访问C++的数据成员。由于this指针的原因，使得一个普通成员函数作为回调函数时就会因为隐含的this指针问题使得函数参数个数不匹配，从而导致回调函数编译失败。 原文链接注：C++静态成员函数与静态数据成员不同，静态成员函数的作用不是为了对象之间的沟通，而是为了能处理静态数据成员。静态成员函数没有this指针。既然它没有指向某一对象，也就无法对一个对象中的非静态成员进行默认访问（即在引用数据时不指定对象名）。静态成员函数和非静态成员函数的根本区别：非静态成员函数有this指针，而非静态成员函数没有this指针。由此决定了静态成员函数不能访问本类中的非静态成员。静态成员函数可以直接引用本类中的静态数据成员，静态成员函数主要用来访问静态数据成员，而不访问非静态成员。原文链接使用方法全局函数-C写法#include <stdio.h> typedef int(*callback)(int, int); int add(int a, int b, callback p){ return (*p)(a, b); } int add(int a, int b){ return a + b; } int main(int argc, char *args[]){ int res = add(4, 2, add); printf("%d\n", res); return 0; }全局函数-C++写法1-(推荐写法)#include <iostream> typedef int(*callback)(int, int); int add(int a, int b) { return a + b; } int Print(callback p, int a, int b) { std::cout << p(a, b) << std::endl; return 0; } int main() { Print(add, 1, 2); system("pause"); return 0; }全局函数-C++写法2#include <iostream> int add(int a, int b) { return a + b; } int Print(int(*callback)(int, int), int a, int b) { std::cout << callback(a, b) << std::endl; return 0; } int main() { Print(add, 1, 2); system("pause"); return 0; }静态类函数无需指明类对象只能访问到类的静态变量，（除非将调用对象作为参数传入静态函数，不推荐）链接举例#include <iostream> typedef int(*callback)(int); class classA { public: static int classA::m_i; static int classA_cb(int i)//静态函数没有this指针，只能访问到静态成员 { m_i = 0; std::cout << i << std::endl; return m_i; }; }; int classA::m_i = 0; //静态成员是该类所有对象唯一的,静态成员使用之前必须初始化 int test(callback p, int i) { return p(i); } int main() { std::cout << test(classA::classA_cb, 1) << std::endl;//因为函数是静态的，所以，使用方式类似全局函数 system("pause"); return 0; }非静态类函数-指定类并提供调用的对象非静态函数，必须指定函数所在类，然后传入类的对象。如果是类调用自身的非静态成员函数，则不需要传入对象。#include <iostream> class MyClass; t…

C++STL—常用算法
type: item
date: 2022-05-26T17:35:00+08:00
description: STL—常用算法零、概述算法主要是由头文件<algorithm>,<functhionla>,<numeric>组成。<algorithm>是所有STL头文件最大的一个，范围涉及到比较，交换，查找，遍历操作，复制，修改等等<numeric>体积很小，只包括几个在序列上面进行简单数学运算的模板函数<functhionla>定义了一些模板类，用以声明函数对象一、常用遍历算法1.for_each-遍历容器#include <iostream> #include <vector> #include <algorithm> using namespace std; void myPrint(const int & i) { cout << i << endl; } class mprint { public: void operator ()(const int & i) { cout << i << endl; } }; int main() { vector <int> mv; for (int i = 1; i<=3 ; i++) { mv.push_back(i); } //for_each(mv.begin(), mv.end(), myPrint);//自定义函数输出 for_each(mv.begin(), mv.end(), mprint());//仿函数输出法 system("pause"); }2.transform-搬运到另一个容器中transform(iterator beg1, iterator end1, iterator beg2,_func);beg1 源容器开始迭代器end1 源容器结束迭代器beg2 目标容器开始迭代器end2 目标容器结束迭代器_func 函数或者函数对象目标vector容器必须先分配好空间#include <iostream> #include <vector> #include <algorithm> using namespace std; int myTrans(const int & i) { cout << i << endl; return i; } class myTran { public: int operator()(const int & i) { return i+1; } }; void myPrint(const int & i) { cout << i << endl; } int main() { vector <int> mv; for (int i = 1; i<=5 ; i++) { mv.push_back(i); } vector<int> mv2; mv2.resize(mv.size());//需要重新设置大小、否则会报错 for_each(mv.begin(), mv.end(), myPrint);//仿函数法 transform(mv.begin()+1, mv.end(), mv2.begin(), myTran());//仿函数法 for_each(mv.begin(), mv.end(), myPrint);//仿函数法 system("pause"); }二、常用查找算法find //查找元素 find_if //按条件查找元素 adjacent_find //查找相邻重复元素 binary_search //二分查找法 count //统计元素个数 count_if //按条件统计元素个数1.find-查找指定元素查找指定元素，找到返回指定元素的迭代器，找不到返回结束迭代器find(iterator beg, iterator end, value)beg 开始迭代器end 结束迭代器value 查找的元素内置数据类型#include <iostream> #include <vector> #include <algorithm> using namespace std; void test() { vector<int> mv; for(int i =0; i<=10;i++) { mv.push_back(i); } //查找容器中是否有5这个元素 vector<int>::iterator it = find(mv.begin(), mv.end(), 5); if (it == mv.end()) { cout<<"error"<<endl; return; } else { cout << *it << endl; } } int main() { test(); system("pause"); return 0; } 自定义数据类型自定义数据类型必须重载自定义数据类型的==运算符#include <ios…

C++STL内建函数
type: item
date: 2022-05-25T18:46:00+08:00
description: 内建函数一、内建函数对象的意义分类算术仿函数关系仿函数逻辑仿函数必须包含<functional>头文件二、算术仿函数功能描述实现四则运算其中negate是一元运算，其他是二元运算仿函数原型template<class T> T plus<T> //加法仿函数 template<class T> T minus<T> //减法仿函数 template<class T> T multiplies<T> //乘法仿函数 template<class T> T divides<T> //除法仿函数 template<class T> T modulus<T> //取模仿函数 template<class T> T negate<T> //取反仿函数#include <iostream> #include <functional> using namespace std; void test1() { negate<int> mni;//取反 cout << mni(50) << endl; } void test2() { plus<int> mpi;//返回值，两个参数的类型底层是写的相同的，所以只用写一个 cout << mpi(10, 50) << endl; } void test3() { divides<int> mpi;//返回值的类型是int， cout << mpi(10, 3) << endl;//输出为3 } int main() { test1(); test2(); test3(); system("pause"); }三、关系仿函数template<class T> bool equal_to<T> //等于 template<class T> bool not_equal_to<T> //不等于 template<class T> bool greater<T> //大于 template<class T> bool greater_equal<T> //大于等于 template<class T> bool less<T> //小于 template<class T> bool less_equal<T> //小于等于#include <iostream> #include <vector> #include <functional> #include <algorithm> using namespace std; void myPrint(const int & elem) { cout << elem << endl; } void test1() { vector<int> mv; mv.push_back(10); mv.push_back(123); mv.push_back(123); mv.push_back(42); mv.push_back(5); for_each(mv.begin(), mv.end(), myPrint); sort(mv.begin(), mv.end(), greater<int>()); for_each(mv.begin(), mv.end(), myPrint); } int main() { test1(); system("pause"); }四、逻辑仿函数template<class T> bool logical_and<T> //逻辑与 template<class T> bool logical_or<T> //逻辑或 template<class T> bool logical_not<T> //逻辑非#include <iostream> #include <algorithm> #include <functional> #include <vector> using namespace std; void myPrint(int elem) { cout << elem << endl; } logical_not<int> m1; void mlogic_not(int & elem) { elem = m1(elem); } void test1() { vector<int> mv; mv.push_back(1); mv.push_back(0); mv.push_back(0); mv.push_back(1); mv.push_back(5); for_each(mv.begin(), mv.end(), myPrint); for_each(mv.begin(), mv.end(), mlogic_not); for_each(mv.begin(), mv.end(), myPrint); } int main() {…

C++谓词
type: item
date: 2022-05-25T17:51:00+08:00
description: 谓词一、谓词概念返回bool类型的仿函数称为谓词如果operator()接收一个参数，叫一元谓词如果operator()接受两个参数，叫二元谓词1.一元谓词#include <vector> #include <iostream> #include <algorithm> using namespace std; class GreateV { public: bool operator()(int val) { return val > 5; } }; void test1() { vector<int> mv; for (int i = 0; i < 10; i++) { mv.push_back(i); } //查找容器中，有没有大于5的数字 //GreateV()是匿名的函数对象， vector<int>::iterator it = find_if(mv.begin(), mv.end(), GreateV());//返回一个迭代器，条件成立的位置 if (it == mv.end()) { cout << "未找到" << endl; } else { cout << "找到了大于5的数字" << *it <<endl; } } int main() { test1(); system("pause"); }2.二元谓词#include <iostream> #include <vector> #include <algorithm> using namespace std; class printVec { public: void operator()(vector<int> &mv) { for (vector<int>::iterator m = mv.begin(); m!=mv.end();m++ ) { cout << *m << endl; } } }; class Print { public: bool operator()(const int &mv1, const int &mv2) { return mv1 > mv2; } }; void test1() { vector<int> mv; printVec pv;//声明一个仿函数的类 mv.push_back(10); mv.push_back(20); mv.push_back(40); mv.push_back(30); //sort(mv.begin(), mv.end());//默认从小到大排序 sort(mv.begin(), mv.end(), Print());//从大到小 pv(mv); } int main() { test1(); system("pause"); }