C++ 线程
线程
基本用法
构造线程
1 |
|
构造线程
1 |
|
std::vector
声明 vector<int> myVector {1,2,3};
访问元素 myVector[2], 不检查是否越界
修改指定位置 myVector[2] = 33;
如果把一个对象存入容器中,那么容器将存储该对象的副本
vector 的析构函数执行时,会调用容器中每个对象的析构函数
push_back:
1 | std::vector<int> numbers; |
pop_back:
1 | std::vector<int> numbers = {1, 2, 3}; |
size:
1 | std::vector<int> numbers = {1, 2, 3}; |
at:
1 | std::vector<int> numbers = {1, 2, 3}; |
front:
1 | std::vector<int> numbers = {1, 2, 3}; |
back:
1 | std::vector<int> numbers = {1, 2, 3}; |
clear:
1 | std::vector<int> numbers = {1, 2, 3}; |
erase:
1 | std::vector<int> numbers = {1, 2, 3, 4, 5}; |
insert: insert 插入比如使用 myVector.begin() 返回 iterator 明确插入元素位置,不能直接使用数字
1 |
|
empty:
1 |
|
1 | std::vector<int> numbers; |
1 | std::vector<int> numbers = {1, 2, 3}; |
1 | for (auto& item:myVector) { |
其他顺序容器
1 |
|
队列和栈(对 deque 的包装)
1 |
|
map 容器用于保存一系列的键值对数据,与 JavaScript 中的 Map 功用相似
包含头文件:
1 |
定义 std::map 对象:
1 | std::map<KeyType, ValueType> myMap; |
其中,KeyType 是键的数据类型,ValueType 是值的数据类型。
插入键值对:
1 | myMap[key] = value; // 或者 myMap.insert(std::make_pair(key, value)); |
访问元素:
1 | ValueType value = myMap[key]; |
遍历 std::map:
1 | for (const auto& pair : myMap) { |
查找元素:
1 | auto it = myMap.find(key); |
删除元素:
1 | myMap.erase(key); |
判断是否为空:
1 | if (myMap.empty()) { |
合并 map
1 | map<string, string> myMap1{ {"key1","val1"},{"key2","val2"} }; |
获取元素个数:
1 | size_t size = myMap.size(); |
清空 std::map:
1 | myMap.clear(); |
自定义比较函数: 如果键类型不支持比较操作,或者需要自定义排序方式,可以提供一个比较函数或者使用函数对象。
1 | std::map<KeyType, ValueType, CompareFunction> myMap; |
其中,CompareFunction 是用于比较键的函数或者函数对象。
遍历 map
1 | //遍历map容器, |
sset 容器用于存储一系列不重复的元素(不是键值对),与 JavaScript 中的 Set 功用相似
set 接口几乎与 map 相同,主要区别是 set 没有下标操作符(operator[])、insert_or_assign 和 try_emplace 等接口
1 | int main() { |
multiset 和 multimap 允许存储多个相同的元素
unordered_map、unordered_multimap、unordered_set、unordered_multiset用于存储多个元素,每个元素的类型可以不同。元组提供了一个有序的集合,可以方便地将多个值组合在一起。
以下是一些关于元组的基本特点和用法:
包含头文件:
1 |
定义 std::tuple 对象:
1 | std::tuple<T1, T2, ..., Tn> myTuple; // 其中 T1, T2, ..., Tn 是元素的类型 |
初始化元组:
1 | auto myTuple = std::make_tuple(value1, value2, ..., valueN); |
访问元组元素:
1 | std::get<Index>(myTuple); // Index 是元素的索引,从 0 开始 |
或者使用结构化绑定(C++17 及以上):
1 | auto [var1, var2, ..., varN] = myTuple; |
修改元组元素:
1 | std::get<Index>(myTuple) = newValue; |
获取元组大小:
1 | constexpr std::size_t tupleSize = std::tuple_size<decltype(myTuple)>::value; |
比较元组:
1 | bool isEqual = (tuple1 == tuple2); |
遍历元组:
1 | std::apply([](auto&&... args) { /* 处理元组中的元素 */ }, myTuple); |
元组在需要将多个相关的值一起传递或组织时非常有用,尤其是当值的类型不同或者数量不确定时。元组提供了一种更灵活的数据结构,可以在编译时或运行时动态地组织和访问元素。
1 |
|
1 |
|
一种是使用 srand 和 rand 方法,它的取值范围为 0 到 32767
另一种是使用 random_device 类,取值范围为 0 到 4294967295
1 |
|
1 |
|
1 |
|
1 |
|
1 |
|
使用 inline 关键字定义修饰方法
编译器在编译代码时,会把这类方法体放置到调用者的方法内,以提高性能
```c++
inline void print(string& str) {
//
}
1 |
|
可以抛出自定义错误类型,但需要对应类型的 catch 捕获
如果被标记了 noexcept 的方法抛出了异常,那么 C++ 将调用 terminate() 方法终止应用程序
string getPhoneNum() noexcept{
//...
}
try catch 可以捕获深度嵌套的异常(多少层都可以)
简单定义
1 | int var = 4l; // 正确 |
常量 4 和表达式 var + 1 都不是左值(也就是说,它们是右值),因为它们都是表达式的临时结果,而没有可识别的内存位置(也就是说,只存在于计算过程中的每个临时寄存器中)。因此,赋值给它们是没有任何语义上的意义的——我们赋值到了一个不存在的位置。
&& 表示。它允许我们绑定到右值(临时对象、将要销毁的对象)。1 | int&& rvalue = 42; // rvalue 是右值引用 |
1 | template<typename T> |
这里的 print 可以接受左值引用,也能接受右值引用
使用函数指针把函数当做参数传递
```c++
//定义一个函数
void print(string& content) {
cout << content << endl;
}
//函数的第一个参数就是函数指针
void callPrint(void (*f) (string&), string& param) {
f(param); //调用函数指针指向的函数
}
int main() {
string content{ "allen" };
//使用函数指针,把print方法当做参数直接传递给callPrint方法
callPrint(print, content); //输出allen
return 0;
}
1 |
|
1 | //函数对象类型 |
operator()() 的普通的对象1 |
|
[capture](parameters) -> returnType { body }[capture]用于让匿名函数的内部逻辑具备访问匿名函数外部变量的能力(parameters) 用于声明匿名函数的参数-> returnType 是匿名函数返回值类型(返回类型后置,一般可以忽略){ body }是匿名函数的函数体[],不捕获任何外部变量,此时在匿名函数体内使用外部变量都会报错。[=]:按值捕获所有外部变量。[&]:按引用捕获所有外部变量。[x, &y]:x 按值捕获,y 按引用捕获。[&, x]:x 按值捕获,其他变量按引用捕获。[=, &x]:x 按引用捕获,其他变量按值捕获。[this]:捕获匿名函数所在作用域的对象,this 是当前对象的指针,此时不会复制整个对象。[*this]:捕获匿名函数所在作用域的对象的副本,此时会复制整个对象。使用 [=] 或 [&] 捕捉外部变量时,只有在匿名函数体内真正使用到的变量才会被复制或引用
1 | int main() { |
1 | // 注意此方法的返回值是auto类型的,实际上返回的是一个方法指针 |
**在执行一个对象的成员函数时,编译器会为该成员函数自动生成一个指针:this**,这个指针就是调用该成员函数的对象指针。
1 | class ORM { |
执行对象的成员函数时,我们可以在函数体内直接访问对象的成员变量或方法
callYourClassMethod();,翻译成这样的代码:this->callYourClassMethod();1 | //函数重载:整型版本 |
使用模板来编写处理多种数据类型的通用函数,而不是写多个函数重载
1 | // 函数模板 |
编译器在处理 add 调用时,会根据参数类型生成 add 函数的重载实现
只在必要时生成
可以使用 auto 关键字自动推断返回类型
```c++
template <typename T1, typename T2>
auto getBiggerNum(T1 param1,T2 param2) {
// auto 关键字自动推断返回类型
return param1 > param2 ? param1 : param2;
}
int main() {
int a{ 123 };
double b{ 987.23 };
auto result = getBiggerNum(a, b);
cout << result << endl; //输出:987.23
auto c = getchar();
}
1 |
|
#include
#include
using namespace std;
//模板类:键值对
template
class KeyValPair
{
public:
KeyValPair(string k, T v) :key{ k }, value{ v } { };
string key;//键
T value; //值
};
//模板类:键值字典
template
class Dic
{
public:
Dic()=default;
void PushBack(KeyValPair
vect.push_back(val);
}
auto operator[](string key) {
for (KeyValPair
{
if (pair.key == key) {
return pair.value;
}
}
}
vector<KeyValPair
};
//使用模板类
int main() {
Dic
// { “test1” , 123 } 直接用于创建KeyValPair对象
dic.PushBack({ “test1” , 123 });
dic.PushBack({ “test2” , 456 });
dic.PushBack({ “test3” , 789 });
cout << dic[“test2”] << endl; //输出456
auto c = getchar();
}
1 |
|
非类型模板参数不代表一个具体的数据类型,而是一个常量表达式
1 |
|
RAII (Resource Acquisition Is Initialization) 用于一个实例离开作用域时自动释放已获取资源
1 |
|
-> 或 * 解引用访问代理对象. 访问自身的管理方法自动释放关联的堆空间
同一对象可被多个共享指针持有
定义方法
```c++
shared_ptr
1 |
|
成员函数
自动释放关联的堆空间
同一对象只能被一个独占指针持有
定义方法
1 |
|
成员函数
用来解决共享指针的循环引用问题
语法 class TextMessage: public Message
子类成员初始化列表可以调用父类的构造函数
TextMessage() : Message(123) {}子类不继承父类构造函数
实例创建和销毁流程

子类继承父类的成员,可以拓展新成员,同名的会覆盖
Message::HidenProperty1 | void Send(Message& msg) { |
可以把子类对象的引用当作父类对象的引用使用
重写
父类方法标记为虚函数
virtual void SendMessage() { }子类重写
void SendMessage() override {...}override 关键字不必须的,但可以编译期检查
包含纯虚函数的类就是抽象类,抽象类是不能实例化的
virtual void SendMessage() = 0重写子类析构函数要把父类设为虚析构函数
virtual ~Message() {...}1 | // Message.h |
1 |
|
1 | // 实际使用 |
static 关键字标记静态成员inline 关键字成为内联的静态成员变量int Message::MsgCount{0};msg->MsgCountMessage::MsgCount 推荐使用这个1 | //头文件,public节 |
将一个对象的值赋值给另一个对象
不推荐使用这个特性
```c++
// 定义
class MyClass {
public:
// 类的成员和其他方法
// 赋值运算符重载
MyClass& operator=(const MyClass& other) {
// 实现赋值操作
if (this != &other) { // 避免自赋值
// 复制 other 的数据到当前对象
// ...
}
// 返回当前对象的引用
return *this;
}
};
1 |
|
如果没有手动创建,编译器会自动生成一个赋值运算符函数
obj2 = obj1可以使用 delete 手动删除
YourType operator= (const YourType& msg) = delete;不推荐使用这个特性
编译器默认生成
复制一个实例
1 |
|
来源于 C 语言
类似 class
默认成员都是 public
struct MyStruct
{
int a = 2;
void func() {
cout << "func:" << endl;
}
};
int main() {
MyStruct myStruct;
myStruct.func();
}
常用来聚合数据