0%

简介

用最简单的术语来说,一个只能应用于函数的 consteval 关键字, 保证它产生一个编译时间常数。否则会导致编译错误。

cppreference 页面对 consteval 说明符有如下描述:

consteval 指定函数是立即函数,也就是说,对该函数的每次调用都必须产生一个编译时常量

什么是立即函数?

  • 不能是协程
  • 函数主体中不能有 throw 语句
  • 不能有 goto 语句或标签语句,除了 casedefault
  • 参数和返回类型必须是LiteralType,简单地说,是一个可以在编译时计算的类型(比如所有可以在 constexpr 上下文中使用的类型)
阅读全文 »

C++ 中,存储变量的方式有几种:

  • 存储期(Storage Duration):
    存储期是指变量在程序中存在的时间段。在 C++ 中,有三种主要的存储期:

    • 自动存储期(Automatic Storage Duration):变量在函数或代码块执行时创建,函数执行结束时销毁。
    • 动态存储期(Dynamic Storage Duration): 使用 newmalloc 分配的内存,直到使用 deletefree 手动释放为止。
    • 静态存储期(Static Storage Duration): 变量在程序启动时创建,在整个程序运行期间都存在,直到程序结束才销毁。
  • 静态存储变量:

静态存储变量是在程序启动时创建,一直存在于整个程序运行期间的变量。这类变量有两种主要形式:

  • 全局变量(Global Variables): 在函数外部声明的变量,可以被程序中的所有函数访问。
  • 静态局部变量(Static Local Variables): 在函数内部使用 static 关键字声明的变量,与自动存储期变量不同,它在函数调用之间保持其值。

C++ 中,我们经常使用静态存储期变量,包括全局变量和使用 static 关键字声明的局部变量。然而,这些变量并不保证在程序执行前被初始化,除非它们被声明为 const 常量。为了解决这一问题,C++20 引入了 constinit 关键字,它为我们提供了一种保证变量在程序启动时被初始化的方式,从而增强了可预测性和可靠性。

尽管 constinit 确保变量在程序启动时被初始化,但这并不意味着这些变量是不可修改的常量。相反,这个关键字允许变量在初始化后在运行时或编译时上下文中被修改。

因此,constinit 关键字为我们提供了一种在使用静态存储期变量时获得初始化保证的方法,同时允许在初始化后对其进行适当的修改。

阅读全文 »

Accessibility Preference Pane

1
2
3
4
5
6
7
8
9
10
11
Main    x-apple.systempreferences:com.apple.preference.universalaccess
Display x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_Display
Zoom x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_Zoom
VoiceOver x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_VoiceOver
Descriptions x-apple.systempreferences:com.apple.preference.universalaccess?Media_Descriptions
Captions x-apple.systempreferences:com.apple.preference.universalaccess?Captioning
Audio x-apple.systempreferences:com.apple.preference.universalaccess?Hearing
Keyboard x-apple.systempreferences:com.apple.preference.universalaccess?Keyboard
Mouse & Trackpad x-apple.systempreferences:com.apple.preference.universalaccess?Mouse
Switch Control x-apple.systempreferences:com.apple.preference.universalaccess?Switch
Dictation x-apple.systempreferences:com.apple.preference.universalaccess?SpeakableItems
阅读全文 »

什么是TLS False Start?

TLS 协商第二阶段,浏览器发送 ChangeCipherSpecFinished 后,立即发送加密的应用层数据,而无需等待服务器端的确认。

如何启用TLS False Start?

  • 需要支持 NPN/ALPN
  • 服务器端配置支持前向安全(Forward Secrecy)

Introduction

ALPN(Application-Layer Protocol Negotiation)应用层协议协商, 当单个服务器端口号(例如端口 443)上支持多个应用程序协议时,客户端和服务器需要协商用于每个连接的应用程序协议。希望在不增加客户端和服务器之间的网络往返次数的情况下完成此协商,因为每次往返都会降低最终用户的体验。

ALPN 作为 TSL的扩展,客户端会将支持的应用程序协议列表作为 TLS ClientHello 消息的一部分发送给服务器,服务器选择一个协议,并将所选协议作为 TLS ServerHello 消息的一部分发送给客户端。因此,可以在 TLS 握手中完成应用协议协商,而无需添加网络往返,并且允许服务器根据需要,将不同的证书与每个应用协议相关联。

阅读全文 »

背景

高级语言经过编译器将源码转为机器指令运行,其中的运行顺序和代码中的顺序有很大差异,主要是下面三个原因:

  • 编译器重排
  • CPU 乱序执行
  • 存储器硬件设计,不同线程看到的顺序不一致。

c++ 中线程同步只有两种方式:

  • 原子变量进行同步
  • 锁(Mutex)

这里我们主要讨论原子变量的操作。

Memory Order

C++11 规定了六种不同的 memory order:

  • Relaxed
  • Consume
  • Acquire
  • Release
  • Acquire-Release
  • Sequential Consistent
    阅读全文 »

joindetach

  • join 或者 detach 只能调用一次

    当调用 join 或者 detach 之后会将持有的线程ID置为 0, 再次调用会抛异常。

    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
    void
    thread::join()
    {
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
    ec = __libcpp_thread_join(&__t_);
    if (ec == 0)
    __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
    __throw_system_error(ec, "thread::join failed");
    }

    void
    thread::detach()
    {
    int ec = EINVAL;
    if (!__libcpp_thread_isnull(&__t_))
    {
    ec = __libcpp_thread_detach(&__t_);
    if (ec == 0)
    __t_ = _LIBCPP_NULL_THREAD;
    }

    if (ec)
    __throw_system_error(ec, "thread::detach failed");
    }
阅读全文 »

Grid

fr

1
2
3
grid-template-columns: 1fr, 1fr, 1fr, 1fr;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: 1fr, 1fr, 1fr, auto;

grid-column

1
2
3
4
grid-column: 1
grid-column: 1 / 4;
grid-column: 1 / span 3;
grid-column: 1 / -1;