C++学习笔记 & 用法快速查询库

导语:本文档整理学习中的遇到的常用语法和c++11以来的新特性,选取了一些经典的例子,用于复习和快速查询

1、STL容器&迭代器

1.1、整体介绍

c++标准模板库提供了一个容器集,针对不同的需要有不同类型的容器

分类容器
序列容器vector、list、deque
容器适配器queue、stack、priority_queue
关联式容器set、map、multiset、multimap

1.1.1、顺序容器&关联容器

顺序容器:容器中的元素的顺序与其加入容器时的位置相对应
关联容器:元素按照 关键字 来保存于访问

1.1.2、 容器适配器

三个容器适配器,提供常用数据结构给开发者带来了便利:即使用容器实现数据结构中的栈、队列。默认情况下,stack和queue是基于deque实现的,priority_quque是在vector上实现的。

1.2、顺序容器

1.2.1、vector

函数编号名称说明
1vector.push_back() &vector.emplace_back()在末尾加入元素
2vector.pop_back()删除末尾元素
3vector.empty()判断向量是否为空,常常与删除元素结合
4vector.size()获取元素个数
5vector.begin()获取起始元素地址
6vector.end()获取最后元素地址
7<algorithm>中的sort()STL中排序函数可以实现vector的排序
8<algorithm>中的reverse()STL中翻转函数可以实现vector的首尾翻转
9vector.front()获取首元素
10vector.back()获取尾元素
11vector.insert() & vector.emplace()插入元素
12vector.erase()删除元素
1.2.1.1 常规操作

代码示例如下:

	#include<iostream>
	#include<vector>
	#include<algorithm>
	using namespace std;
	 
	 
	int main()
	{		
        // 加入元素后打印
        vector<int> v;
		v.push_back(5);
		v.push_back(6);
		v.push_back(1);
        v.push_back(23);
		for (int i = 0; i < v.size(); i++)
			cout << v[i] << " ";
	    cout << endl;

        // 排序元素后打印
		sort(v.begin(), v.end());
		for (int i = 0; i < v.size(); i++)
			cout << v[i] << " ";
	    cout << endl;
		
        // 删除尾部元素打印
		if(!v.empty())
			v.pop_back();
		for (int i = 0; i < v.size(); i++)
			cout << v[i] << " ";
		cout << endl;
		
        // 加入元素(string类)后打印
		vector<string> str;
		str.push_back("hulk");
		str.push_back("c++");
		for (int i = 0; i < str.size(); i++)
			cout << str[i] << " ";
        cout << endl;
	 
        // 使用insert、emplace加入元素后auto打印
		v.insert(v.end(),1);
		v.emplace(v.begin()+1,2);
		for(auto loop:v){
			cout << loop <<" ";
		}
        cout << endl;
	 
        // 迭代器打印
		vector<int>::iterator it;
	    for(it=v.begin(); it!=v.end();it++)  
	    {  
	        cout<<*it<<" ";  
	    }  
	    cout<<endl;
	 
	    return 0;
	}
1.2.1.2 vector.resize
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> c = {1, 2, 3};
    std::cout << "The vector holds: ";
    for (const auto& el: c)
        std::cout << el << ' ';
    std::cout << '\n';

    c.resize(5);
    std::cout << "After resize up to 5: ";
    for (const auto& el: c)
        std::cout << el << ' ';
    std::cout << '\n';

    c.resize(2);
    std::cout << "After resize down to 2: ";
    for (const auto& el: c)
        std::cout << el << ' ';
    std::cout << '\n';

    c.resize(6, 4);
    std::cout << "After resize up to 6 (initializer = 4): ";
    for (const auto& el: c)
        std::cout << el << ' ';
    std::cout << '\n';
}

output

The vector holds: 1 2 3 
After resize up to 5: 1 2 3 0 0 
After resize down to 2: 1 2 
After resize up to 6 (initializer = 4): 1 2 4 4 4 4
1.2.1.3 vector.erase()
#include <iostream>
#include <vector>
using namespace std;
 
int main(){
    vector<int> vec = {10, 20, 30, 40}; // 创建包含四个元素的向量
    
    int elementToRemove = 30; // 需要删除的元素值为30
    
    for (auto it = vec.begin(); it != vec.end(); ++it){
        if (*it == elementToRemove) {
            vec.erase(it); // 在迭代器指向的位置上删除该元素
            break; // 只删除第一次遇到的元素,若有多个相同元素则会重复删除
        }
    }
    
    cout << "删除后的向量内容:";
    for (const auto& num : vec){
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

output:
删除后的向量内容:10 20 40

1.2.2、list

1.3、容器适配器

1.3.1、queue

核心接口:push/front/back/pop

#include <iostream>
#include <queue>
using namespace std;

int main() {
    queue<int> myQueue;
    myQueue.push(1);
    myQueue.push(2);
    cout << myQueue.front();
    myQueue.pop();
    cout << myQueue.front();
    return 0;
}

结果

12

1.3.2、stack

核心接口: push/pop/top

1.3.3、priority queue

#include <iostream>
#include <queue>
using namespace std;

int main() {
    priority_queue<int> q;
    priority_queue<int, vector<int>, greater<int> > c;

    for (int n : {1,8,5,6,3,4,0,9,7,2}) {
        q.push(n);
        c.push(n);
    }

    while (!q.empty()) 
    {
        cout << q.top() << ' ';
        q.pop();
    } 
    cout << endl;
    while (!c.empty()) 
    {
        cout << c.top() << ' ';
        c.pop();
    } 

    return true;
}

1.4、关联容器

关联容器支持高效的关键字查找和访问:

  • 如map关键字起到索引的作用,值则是与索引相关联的数据

关联容器分为:

  • 有序和无序的

无序容器:

  • 无序容器不是使用比较运算符来组织元素,而是使用哈希函数和关键字类型的==运算符
  • 由于无序容器不需要维护元素的序,性能会更好

1.4.1、map

函数编号名称说明
1map.count(key)有该元素返回1,否则0
#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
    std::map<int, char> m;
    m[11] = 'a';
    m[2] = 'b';
    m[3] = 'c';
    using rit_t = std::map<int, char>::iterator;
    for (rit_t it = m.begin(); it != m.end(); ++it) {
        it->second = 'c';
    }
    using const_rit_t = std::map<int, char>::const_iterator;
    for (const_rit_t it = m.begin(); it != m.end(); ++it) {
        std::cout << "key: " << it->first << " value: "
    << it->second << std::endl;
    }

    std::map<string, int> v;//此时比较的是内容
    const string a = "bello";
    const string b = "aorld";
    v[a] = 1;
    v[b] = 2;

    using rit_a = std::map<string, int>::iterator;
    for (rit_a it = v.begin(); it != v.end(); ++it) {
        std::cout << "key: " << it->first << " value: "
    << it->second << std::endl;
    }

    return true;
}

输入结果如下:

#include <iostream>
#include <map>
using namespace std;

int main() {
    map<int, int> myMap{{1,1},{2,2},{3,3}};
    auto it = myMap.insert(myMap.begin(), {4,4});
    cout << it->first << ' ' << it->second  << endl;
    for (const auto& [key, value] : myMap) {  // c++ 17
        cout << '[' << key << ']' << " = " << value << endl;
    }
    return true;
}

output

4 4
[1] = 1
[2] = 2
[3] = 3
[4] = 4

insert(iter, pair<…>)返回一个指向插入元素的迭代器,如果map中已经存在元素,则返回的迭代器指向原先map中已经存在的元素
erase 返回下一个迭代器

2、结构体排序

	struct Message {
	    int start;
	    int load;
	};
	 
	vector<Message> messages;
	 
	static bool com(const Message &a,const Message &b) {
	    return a.start < b.start;
	}
	 
	sort(messages.begin(),messages.end(),com);

3、STL算法

标准库中定义了100多个算法,大部分定义在头文件algorithm中,numeric文件中定义了一些数值泛型算法

3.1、for_each

for_each(InputIt first, InputIt last, UnaryFunction f);

  • first, last:要应用函数的元素范围
  • f:函数对象,要应用于解引用范围 [first, last) 中每个迭代器结果的函数
void output(int v)
{
std::cout << v << std::endl;
}

std::vector<int> nums{1, 2, 3};
std::for_each(data.begin(), data.end(), output);

3.2、 count

count(InputIt first, InputIt last, const T &value)

  • first, last:要应用函数的元素范围
  • value:特定元素值

3.3、count_if

count_if(InputIt first, InputIt last, UnaryPredicate p)

  • first, last:要应用函数的元素范围
  • p:函数对象,要应用于解引用范围 [first, last) 中每个迭代器结果的函数,返回true表示满足条件

3.4、find

find(inputIt first, inputIt last, const T &vaule)

  • first, last:要应用函数的元素范围
  • value:特定元素值
  • 返回:指向首个满足条件的迭代器,或若找不到这种元素则为last

3.5、find_if

find_if(inputIt first, inputIt last, UnaryPredicate p)

  • first, last:要应用函数的元素范围
  • p:函数对象,要应用于解引用范围[first, last)中每个迭代器结果的函数,返回true表示满足条件
  • 返回:指向首个满足条件的迭代器,或若找不到这种元素则为last

3.6、binary_search

  • 使用二分搜索的方法查找元素,比较次数O(logN)
  • 输入要求:输入序列中的元素是有序的
vector<int> haystack{1,2,3,4,5};
vector<int> needles{1,2,3};

for (auto needle : needles) {
	if (binary_search(haystack.begin(), haystack.end(), needle)) {
		cout << "found" << needle << endl;
	}
}

3.7、all_of

all_of(inputIt first, inputlt last, UnaryPredicate p)

vector<int> data{1,2,3,4,5};
bool result = all_of(data.begin(), data.end(), [](int v){return (v > 5);}

3.8、any_of

any_of(InputIt first, InputIt last, UnaryPredicate p)

3.9、copy

copy(InputIt first, InputIt last, OutputIt d_first)

3.10 copy_if

copy_if(InputIt first, InputIt last, OutputIt d_first, UnaryPredicate p)

3.11、replace_if

replace(InputIt first, InputIt last, old_val, new_val)

3.12、sort

sort(InputIt first, InputIt last)
sort(InputIt first, InputIt last, UnaryPredicate p)

3.13、reverse

reverse(InputIt first, InputIt last);

3.14、补充

int a =0, b = 1;
auto f1=[]{return a;};//error,没有捕获外部变量
auto f2=[&]{return a++;};//ok,捕获所有外部变量,并对a执行自加运算
auto f3=[=]{return a;};//ok,捕获所有外部变量,并返回a
auto f4=[=]{return a++;};//error,a以复制方式捕获
auto f5=[a]{return a+b;};//error,没有捕获变量b
auto f6=[a,&b]{return a+(b++);};//ok,捕获a和b引用
auto f7=[=,&b]{return a+(b++);};//ok,捕获所有外部变量和b引用

4 数学库

#include <cmath>

4.1 对数函数

logm(n) = log(n)/log(m)

4.2 向上取整

ceilf(n)

5 并发编程

从C++11开始,在语言的级别引入了线程的概念,C++11 新标准中引入了几个头文件来支持多线程编程:
几个重要头文件: <condition_variable>

5.1 原子操作

所谓的原子操作,取的就是“原子是最小的、不可分割的最小个体”的意义,它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。

#include <iostream>
#include <atomic>
#include <thread>


std::atomic<int> foo(0);


void set_foo(int x) {
foo.store(x, std::memory_order_relaxed);
}




void print_foo() {
int x = 0;
do {
x = foo.load(std::memory_order_relaxed);
} while (x == 0);
std::cout << "foo:" << x << '\n';
}




int main() {
std::thread first(print_foo);
std::thread second(set_foo, 10);
first.join();
second.join();
return true;
}

5.2 互斥锁(同步)

在多任务操作系统中,同时运行的多个任务可能都需要使用同一种资源。这个过程有点类似于,公司部门里,我在使用着打印机打印东西的同时(还没有打印完),别人刚好也在此刻使用打印机打印东西,如果不做任何处理的话,打印出来的东西肯定是错乱的。

在线程里也有这么一把锁——互斥锁(mutex),互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即上锁( lock )和解锁( unlock )。

【互斥锁的特点】:

  1. 原子性:把一个互斥量锁定为一个原子操作,这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

  2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

  3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

【互斥锁的操作流程如下】:

  1. 在访问共享资源后临界区域前,对互斥锁进行加锁;

  2. 在访问完成后释放互斥锁导上的锁。在访问完成后释放互斥锁导上的锁;

  3. 对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。


#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>


std::mutex mtx;


void print_even(int x) {
if (x % 2 == 0) {
std::cout << x << "is even\n";
}else {
throw(std::logic_error("not even"));
}
}


void print_thread_id(int id) {
try {
std::lock_guard<std::mutex> lck(mtx);
print_even(id);
}
catch(std::logic_error&) {
std::cout << "[exception caught]\n";
}
}


int main() {
std::thread threads[10];
for (int i = 0; i<10; i++) {
threads[i] = std::thread(print_thread_id, i+1);
}


for (auto& th :threads) {
th.join();
}


return true;
}

5.3 条件变量(同步)

与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直 到某特殊情况发生为止。通常条件变量和互斥锁同时使用。

条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步 的一种机制,主要包括两个动作:

一个线程等待"条件变量的条件成立"而挂起;

另一个线程使 “条件成立”(给出条件成立信号)。

【原理】:

条件的检测是在互斥锁的保护下进行的。线程在改变条件状态之前必须首先锁住互斥量。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量 可以被用来实现这两进程间的线程同步。

【条件变量的操作流程如下】:

  1. 初始化:init()或者pthread_cond_tcond=PTHREAD_COND_INITIALIER;属性置为NULL;

  2. 等待条件成立:pthread_wait,pthread_timewait.wait()释放锁,并阻塞等待条件变量为真 timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait);

  3. 激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)

  4. 清除条件变量:destroy;无线程等待,否则返回EBUSY清除条件变量:destroy;无线程等待,否则返回EBUSY

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>


std::mutex mtx;
std::condition_variable cv;
int ready = false;


void print_id(int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) {
cv.wait(lck);
}
std::cout << "thread" << id << '\n';
}


void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}


int main() {
std::thread threads[10];
for (int i = 0; i < 10; i++) {
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race...\n";
go();
for(auto& th : threads) {
th.join();
}
return true;
}

6 函数指针

6.1 代码实现

#include <iostream>
using namespace std;
#define IDM_GLOBAL_REG_EXECUTE(varName_, ...)                    \
    namespace {                                                  \
    auto g_globalVarReg##varName_ __attribute__((used)) = []() { \
        __VA_ARGS__;                                             \
        return 0;                                                \
    }();                                                         \
    }
#define REG_RTPC_INIT(boardTypeNameList, func) IDM_GLOBAL_REG_EXECUTE(boardTypeNameList##Init, set_func(func))

typedef void *(*rpc_service_func_t)(unsigned int func_id, void *arg1, void *arg2, void *arg3, void *arg4);

void *service_func_test(unsigned int func_id, void *arg1, void *arg2, void *arg3, void *arg4)
{
    cout << *(int *)arg1 << endl;
    return arg1;
}

rpc_service_func_t func_test;

void set_func(rpc_service_func_t func)
{
    func_test = func;
}

void get_func(rpc_service_func_t &func)
{
    func = func_test;
}

REG_RTPC_INIT(aa, service_func_test)
int main()
{
    // set_func(service_func_test);
    rpc_service_func_t func;
    get_func(func);
    int a = 5;
    func(1, &a, 0, 0, 0);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值