数组退化

数组通常会退化为指针。为了避免退化可以使用模板函数 + 引用参数的形式。

1
2
3
4
5
template <typename T>
void h(T& param);

int arr[10];
h(arr);

这里 T 只能被推导为 int[10]。(只使用模板函数还是无法避免退化,会将T推导为指针)

extern

声明一个变量,告诉编译器它在别的地方有定义。通常将extern声明放到头文件中,将定义放到某个源文件中。这样所有使用该头文件的文件头会获得该声明,但是定义只有一份。

套接字-又名socket

套接字层(Socket Layer)位于 应用层和传输层之间套接字 是一个抽象层,它提供了一个编程接口,让应用程序(应用层)可以调用操作系统提供的功能来使用传输层和网络层的服务。

返回右值

分为两种情况,

  • 返回一个临时对象,比如 return object()
  • 通过std::move 返回一个右值引用,注意返回的右值引用仍然是引用。比如下面的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;
class B{
public:
B() :ptr(new int[10]) {}
B(B&& b){
std::cout << "开始 移动构造函数\n";
this->ptr = b.ptr;
b.ptr = 0;
}
~B(){
std::cout << "开始析构" << std::endl;
if (ptr)
delete[] ptr;
}
private:
int* ptr;
};
B&& f()//注意这里B&&
{
B tmp;
return std::move(tmp);
}
int main()
{
B b1(f());
return 0 ;
}
*****************************************************
开始析构
开始 移动构造函数
Segmentation fault (core dumped)

这里通过f()返回右值引用后,理论上可以触发B 的移动构造函数,但是这并不是在返回语句执行时开始构造的,而是在f()函数执行完即其内部的局部对象被析构完成后才执行的。等待移动构造函数执行时,会发现引用的对象不存在了。

时钟选择

std::chrono::steady_clock:特点:

  • 单调递增(不会倒退)
  • 不受系统时间调整影响

用途:测量时间间隔、性能分析

std::chrono::system_clock:代表系统实际时间,可用于打印日志时间戳。几个重要的概念:

  • 时间点,表示某个绝对的时间点(本质上是从 epoch(1970-01-01)开始的时间偏移量)
  • 时间段,比如std::chrono::milliseconds,可以用于表示时间段,比如milliseconds ms(1500)表示1.5秒。时间段可以通过count来获取获取具体的数值。

std::chrono::system_clock::now()返回当前的时间点。

线程状态

当一个线程被创建时,它有两种可能的状态:

  1. 可连接的(joinable):这是默认状态。当线程结束时,它的资源(如线程 ID、栈空间等)不会立即被操作系统回收。你必须显式地调用 pthread_join() 函数来等待该线程结束,并回收其资源。如果不这么做,这些资源会一直占用,导致内存泄漏。
  2. 可分离的(detached):当线程被设置为分离状态后,如果它运行结束,其所有资源会自动被操作系统回收。你无法再调用 pthread_join() 来等待它或获取其返回值。

BUG:qualified name is not allowed

有可能是,使用了限定符,但是没有include头文件导致的。

线程局部变量动态初始化

c++11开始,使用了thread_local关键字,可以实现动态初始化。(c++11之前的__thread只支持静态初始化)

静态初始化:编译时就能确定初始值,完成初始化。

动态初始化:运行时确定初始值,完成初始化,包括使用函数调用。

防止拷贝重叠

std::copy:要求目标起点不能在源区间之间。

std::copy_backward:从后往前拷贝。

std::memmove:: cstring的函数,自动处理方向。