IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++积累 -> 正文阅读

[C++知识库]C++积累

STL

atomic

?

?

?

?

#include <atomic>

原子操作(atomic): 互斥量的加锁一般是针对一个代码段,而原子操作针对的一般都是一个变量。原子变量既不可复制亦不可移动。(1)它表示在多个线程访问同一个全局资源的时候,能够确保所有其他的线程都不在同一时间内访问相同的资源。也就是他确保了在同一时刻只有唯一的线程对这个资源进行访问。这有点类似互斥对象对共享资源的访问的保护,但是原子操作更加接近底层,因而效率更高。是线程安全的。

(2)原子数据类型不会发生数据竞争,能直接用在多线程中而不必我们用户对其进行添加互斥资源锁的类型。从实现上,大家可以理解为这些原子类型内部自己加了锁。

(3)C++11中所有的原子类都是不允许拷贝、不允许Move的,atomic_flag也不例外。

(4)C++11 对常见的原子操作进行了抽象,定义出统一的接口,并根据编译选项/环境产生平台相关的实现。新标准将原子操作定义为atomic模板类的成员函数,囊括了绝大多数典型的操作——读、写、比较、交换

contained type

atomic type

bool

atomic_bool

char

atomic_char

signed char

atomic_schar

unsigned char

atomic_uchar

short

atomic_short

unsigned short

atomic_ushort

int

atomic_int

unsigned int

atomic_uint

long

atomic_long

unsigned long

atomic_ulong

long long

atomic_llong

unsigned long long

atomic_ullong

wchar_t

atomic_wchar_t

char16_t

atomic_char16_t

char32_t

atomic_char32_t

intmax_t

atomic_intmax_t

uintmax_t

atomic_uintmax_t

int_leastN_t

atomic_int_leastN_t

uint_leastN_t

atomic_uint_leastN_t

int_fastN_t

atomic_int_fastN_t

uint_fastN_t

atomic_uint_fastN_t

intptr_t

atomic_intptr_t

uintptr_t

atomic_uintptr_t

size_t

atomic_size_t

ptrdiff_t

atomic_ptrdiff_t

(4)macro

macro

relative to types

ATOMIC_BOOL_LOCK_FREE

bool

ATOMIC_CHAR_LOCK_FREE

char

signed char

unsigned char

ATOMIC_SHORT_LOCK_FREE

short

unsigned short

ATOMIC_INT_LOCK_FREE

int

unsigned int

ATOMIC_LONG_LOCK_FREE

long

unsigned long

ATOMIC_LLONG_LOCK_FREE

long long

unsigned long long

ATOMIC_WCHAR_T_LOCK_FREE

wchar_t

ATOMIC_CHAR16_T_LOCK_FREE

char16_t

ATOMIC_CHAR32_T_LOCK_FREE

char32_t

ATOMIC_POINTER_LOCK_FREE

U*

(for any type?U)

(5)memory_order:内存顺序

序号

意义

1

memory_order_relaxed

宽松模型,不对执行顺序做保证

2

memory_order_consume

当前线程中,满足happens-before原则。

当前线程中该原子的所有后续操作,必须在本条操作完成之后执行

3

memory_order_acquire

当前线程中,操作满足happens-before原则。

所有后续的操作必须在本操作完成后执行

4

memory_order_release

当前线程中,操作满足happens-before原则。

所有后续的操作必须在本操作完成后执行

5

memory_order_acq_rel

当前线程中,同时满足memory_order_acquire和memory_order_release

6

memory_order_seq_cst

最强约束。全部读写都按顺序执行

(6)Functions

(7)std::atomic的限制:trivially copyable(可平凡复制)一个类型如果是trivially copyable,则使用memcpy这种方式把它的数据从一个地方拷贝出来会得到相同的结果。

1.没有non-trivial 的拷贝构造函数

2.没有non-trivial的move构造函数

3.没有non-trivial的赋值操作符

4.没有non-trivial的move赋值操作符

5.有一个trivial的析构函数

std::atomic_flag:最简单的原子变量实例是对于bool类型的变量进行原子操作,提供了标志的管理,标志有三种状态:clear、set和未初始化状态。

接口介绍:

(1)ATOMIC_FLAG_INIT:用于给atomic_flag变量赋初值,如果定义后为赋值,则状态是不确定的。被这个赋值后的状态为false。

(2)test_and_set() 接口函数,调用后状态变为true,并返回改变状态前的状态值

(3)clear() : 接口函数,调用后状态变为false。

?

#include <thread>

#include <vector>

#include <iostream>

#include <atomic>

std::atomic_flag lock = ATOMIC_FLAG_INIT;

int gcnt = 0;

void f(int n)

{

??? for (int cnt = 0; cnt < 100; ++cnt) {

??????? while (lock.test_and_set(std::memory_order_acquire))? // 获得锁

???????????? ; // 自旋

??????? std::cout << "Output from thread " << n << '\n';

??????? gcnt++;

??????? lock.clear(std::memory_order_release);?????????????? // 释放锁

??? }

}

int main()

{

??? std::vector<std::thread> v;

??? for (int n = 0; n < 10; ++n) {

??????? v.emplace_back(f, n);

??? }

??? for (auto& t : v) {

??????? t.join();

??? }

}

自旋锁的解释:当某一个线程调用‘lock.test_and_set’时,即设置lock的状态为true,当另一个线程进入时,再次调用test_and_set时返回的状态为true,则一直在while循环中不断获取,即实现了等待,直到第一个线程调用clear将状态变为false。

std::atomic<T>:通过atomic模板类可以对更多的类型进行原子操作

(1)is_lock_free:通过这个接口判断是否需要加锁。如果是,则在多个线程访问该对象时不会导致线程阻塞(可能使用某种事务内存transactional memory方法实现lock-free的特性)。事实上该函数可以做为一个静态函数。所有指定相同类型T的atomic实例的is_lock_free函数都会返回相同值。

(2)store:赋值操作。operator=实际上内部调用了store,并返回d。

void store(T desr, memory_order m = memory_order_seq_cst) noexcept;
void store(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;
T
operator=(T d) noexcept;
T
operator=(T d) volatile noexcept;

(3)load: 读取,加载并返回变量的值。operator T是load的简化版,内部调用的是load(memory_order_seq_cst)形式。

(4)exchange交换,赋值后返回变量赋值前的值。exchange也称为read-modify-write操作。

T exchange(T desr, memory_order m = memory_order_seq_cst) volatile noexcept;

T exchange(T desr, memory_order m = memory_order_seq_cst) noexcept;

(5)compare_exchange_weak这就是有名的CAS(Compare And Swap: 比较并交换)。操作是原子的,排它的。其它线程如果想要读取或修改该原子对象时,会等待先该操作完成。

(6)compare_exchange_strong:

进行compare时,与weak版一样,都是比较的物理内容。与weak版不同的是,strong版本不会返回伪false。即:原子对象所封装的值如果与expect在物理内容上相同,strong版本一定会返回true。其所付出的代价是:在某些需要循环检测的算法,或某些平台下,其性能较compare_exchange_weak要差。但对于某些不需要采用循环检测的算法而言, 通常采用compare_exchange_strong 更好。

std::atomic特化:

(1)fetch_add该函数将原子对象封装的值加上v,同时返回原子对象的旧值。其功能用伪代码表示为:

// T is integral

T fetch_add(T v, memory_order m = memory_order_seq_cst) volatile noexcept;

T fetch_add(T v, memory_order m = memory_order_seq_cst) noexcept;

// T is pointer

T fetch_add(ptrdiff_t v, memory_order m = memory_order_seq_cst) volatile noexcept;

T fetch_add(ptrdiff_t v, memory_order m = memory_order_seq_cst) noexcept;

(2)fetch_sub该函数将原子对象封装的值减去v,同时返回原子对象的旧值。其功能用伪代码表示为:

// T is integral

T fetch_sub(T v, memory_order m = memory_order_seq_cst) volatile noexcept;

T fetch_sub(T v, memory_order m = memory_order_seq_cst) noexcept;

// T is pointer

T fetch_sub(ptrdiff_t v, memory_order m = memory_order_seq_cst) volatile noexcept;

T fetch_sub(ptrdiff_t v, memory_order m = memory_order_seq_cst) noexcept;

(3)++, --, +=, -=不管是基于整数的特化,还是指针特化,atomic均支持这四种操作。其用法与未封装时一样

独属于数值型特化的原子操作 - 位操作:

(1)fetch_and,fetch_or,fetch_xor:

位操作,将contained按指定方式进行位操作,并返回contained的旧值。

integral fetch_and(integral v, memory_order m = memory_order_seq_cst) volatile noexcept;

integral fetch_and(integral v, memory_order m = memory_order_seq_cst) noexcept;

integral fetch_or(integral v, memory_order m = memory_order_seq_cst) volatile noexcept;

integral fetch_or(integral v, memory_order m = memory_order_seq_cst) noexcept;

integral fetch_xor(integral v, memory_order m = memory_order_seq_cst) volatile noexcept;

integral fetch_xor(integral v, memory_order m = memory_order_seq_cst) noexcept;

(2)perator &=operator |=operator ^=与相应的fetch_*操作不同的是,operator操作返回的是新值

T operator &=(T v) volatile noexcept {return fetch_and(v) & v;}

T operator &=(T v) noexcept {return fetch_and(v) & v;}

T operator |=(T v) volatile noexcept {return fetch_or(v) | v;}

T operator |=(T v) noexcept {return fetch_or(v) | v;}

T operator ^=(T v) volatile noexcept {return fetch_xor(v) ^ v;}

T operator ^=(T v) noexcept {return fetch_xor(v) ^ v;}

thread

#include <thread>

(1)

(2)tread函数:

get_id

获取线程 ID。

joinable

检查线程是否可被join。

join

Join 线程。

detach

Detach 线程

swap

native_handle

hardware_concurrency ?[static]

(1)接口函数:

函数

详解

示例

std::async(std::launch::async,provider);

(1)作用:在于将其获取到的函数立即在一个新的线程内进行异步启动。也就是一个线程启动函数。

(2)std::aysnc()返回:会返回一个std::future object类型的返回值,在std::future object中,我们可以取得线程返回值或异常信息。此外,std::future object类型的特化与线程函数的返回值一致。

(3)指定std::aysnc()的发射策略(launch strategy):

std::async的策略主要有两个:

??? 1、std::launch::async? :? 立即尝试启动异步调用,如果在此处无法进行调用时,会返回一个std::system_error

??? 2、std::launch::deferred : 延缓线程的启动,直到我们手动调用future::get()时,线程才会启动。

(1)示例1std::aysnc(func1) //无参数形式

(2)示例2:

std::aysnc(func1,arg1,arg2) //向函数func1传递arg1,arg2;

(3)示例3:

void func1(int A = 0);

int func2();

int main()

{

std::future<void> func1_res(std::async(print_A,10));

??? ??????//func1返回类型为void,future object的类型也为void

std::future<int> func2_res(std::async(print_B));

??? ???????//func2返回类型为int,future object的类型也为int

}

(4)示例4:

int main()

{

??? //f1在这里就启动了,输出func1 start!

std::future<void> f1(std::async(std::launch::async, func1));

??? //f2在这里由于发射策略的原因,并没有启动

std::future<void> f2(std::async(std::launch::deferred, func2));

Sleep(3000);

std::cout << "3 seconds later!" << std::endl;

??? //三秒之后,由于调用future::get(),线程f2启动,输出func2 start!

f2.get();

return 0;

}

std::future

?

std::shared_future

?

?

?

?

std::thread

(1)作用:

(2)与async比较:

1、Class thread 没有发射策略,只要我们实例化Class thread的对象,系统就会尝试启动目标函数,如果无法启动目标函数,就会抛出std::system_error并携带差错resource_unavailable_try_again。

2、Class thread并不提供处理线程结果的接口

3、必须对线程的状态进行声明,等待其结束(join())或直接卸载(detach())

4、如果main()函数结束了,所有线程会被直接终止

示例1:

std::thread t1(Print, 1); //创建线程1

std::thread t2(Print, 2); //创建线程2

t1.join(); //等待线程1结束

t2.join(); //等待线程2结束

?

std::promise

?

?

packaged_task

(1)作用:实现了运行我们自由控制启动线程的启动时间,可以用于实现线程池

示例1:

std::packaged_task<void()> task(func1);? //这里创建thread task,但是不会立即启动线程

Sleep(3000); //sleep3秒,当然,这里可以改成任何你需要的操作

task(); //3秒后启动线程

(2)互斥量与锁(Mutex & Lock):

std::mutex m_lock;

lock()

?

?

try_lock()

?

?

unlock()

?

?

try_lock_for()

?

?

try_lock_until()

?

?

lock_guard

(1)作用:

(2)使用:

std::lock_guard<T> lg(m_lock) //建立并锁定

std::lock_guard<T> lg(m_lock, adopt_lock) //为已锁定的m_lock建立lock_guard

(1)示例1:

std::mutex m_lock;

std::lock_guard<std::mutex> lg(m_lock);//上锁,超出作用于自动解锁

unique_lock

(1)作用:相对于Class lock_guard 来说,Class unique_lock 的特殊之处在于,可以让我们指定“何时”以及“如何”锁定和结果Mutex,此外,在Class unique_lock中,我们甚至可以用owns_lock()或bool()来查询目前Mutex是否会被锁住。

?

(3)条件变量(Condition Variable

?

?

(4)

()

enable_if_t

?

?

std::enable_if_t<!std::is_same<std::remove_cv_t<T>, A>::value> * = nullptr>

?

?

?

?

enable_if

?

?

is_same

?

?

remove_cv_t

?

?

std::ref

?

?

C++ 关键词

class

用法

class Foo;? // 类的前置声明

class Bar { // 类的定义

? public:

??? Bar(int i) : m_i(i) {}

? private:

??? int m_i;

};

template <class T> // 模板实参

void qux() {

??? T t;

}

int main()

{

??? Bar Bar(1);

??? class Bar Bar2(2); // 详述的类型

}

explicit

用法

explicit

(1)

explicit (?表达式?)

(2)

(C++20 起)

1)?指定构造函数或转换函数?(C++11 )推导指引?(C++17 )为显式,即它不能用于隐式转换复制初始化

2)?explicit?说明符可以与常量表达式一同使用。当且仅当该常量表达式求值为?true?时函数为显式。

(C++20 起)

explicit 说明符只可出现于在类定义之内的构造函数或转换函数?(C++11 )?声明说明符序列?中。

?

struct A
{
??? A(int) { }????? // 转换构造函数
??? A(int, int) { } // 转换构造函数 (C++11)
??? operator bool() const { return true; }
};
?
struct B
{
??? explicit B(int) { }
??? explicit B(int, int) { }
??? explicit operator bool() const { return true; }
};
?
int main()
{
??? A a1 = 1;????? // OK:复制初始化选择 A::A(int)
??? A a2(2);?????? // OK:直接初始化选择 A::A(int)
??? A a3 {4, 5};?? // OK:直接列表初始化选择 A::A(int, int)
??? A a4 = {4, 5}; // OK:复制列表初始化选择 A::A(int, int)
??? A a5 = (A)1;?? // OK:显式转型进行 static_cast
??? if (a1) ;????? // OK:A::operator bool()
??? bool na1 = a1; // OK:复制初始化选择 A::operator bool()
??? bool na2 = static_cast<bool>(a1); // OK:static_cast 进行直接初始化
?
//? B b1 = 1;????? // 错误:复制初始化不考虑 B::B(int)
??? B b2(2);?????? // OK:直接初始化选择 B::B(int)
??? B b3 {4, 5};?? // OK:直接列表初始化选择 B::B(int, int)
//? B b4 = {4, 5}; // 错误:复制列表初始化不考虑 B::B(int,int)
??? B b5 = (B)1;?? // OK:显式转型进行 static_cast
??? if (b2) ;????? // OK:B::operator bool()
//? bool nb1 = b2; // 错误:复制初始化不考虑 B::operator bool()
??? bool nb2 = static_cast<bool>(b2); // OK:static_cast 进行直接初始化
}

friend

说明

友元声明出现于类体内,并向一个函数或另一个类授予对包含友元声明的类的私有及受保护成员的访问权。

语法

friend?函数声明

(1)

friend?函数定义

(2)

friend?详述类说明符?;

(3)

friend?简单类型说明符?;

friend?typename-说明符?;

(4)

(C++11 起)

inline

说明:

用法

export

用法

用于标记模板定义被导出,这允许在其他翻译单元中声明但不定义同一模板。(1)

(C++11 前)

不使用并保留该关键词。

(C++11 起)

(C++20 前)

标记一个声明、一组声明或另一模块为当前模块所导出。

(C++20 起)

export 是可选的修饰符,模板被导出(用于声明类模板时,它也声明其所有成员被导出)。对被导出模板进行实例化的文件不需要包含其定义:声明即已充分。

export module name

  • 导出模块
  • export?template?<?形参列表?>?类声明

(1)

export template <typename T>

class MyClass

{

??? public:

??????? void memfun1();???? // 被导出的函数

??????? void memfun2(){ ... } // 隐式内联不能被导出

??????? ...

??????? void memfun3();????? // 显式内联不能被导出

??????? ...

};

template <typename T>

inline void MyClass<T>::memfun3()?? // 使用inline关键字,显式内联

{

??? ...

}

(2)

// helloworld.cpp
export module helloworld;? // 模块声明
import <iostream>;???????? // import声明
?
export void hello() {????? // export声明
??? std::cout << "Hello world!\n";
}

// main.cpp
import helloworld;? // import声明
?
int main() {
??? hello();
}

extern

用法

extern?字符串字面量?{?声明序列(可选)?}

(1)

extern?字符串字面量?声明

(2)

1)?将语言说明?字符串字面量?应用到声明于?声明序列?中的所有函数类型,具有外部链接的函数名,和具有外部链接的变量。

2)?将语言说明?字符串字面量?应用到单一声明或定义。

字符串字面量

-

所要求的语言链接的名字

声明序列

-

声明的序列,可以包含嵌套的链接说明

声明

-

一个声明

extern?template?class|struct?模板名?<?实参列表?>?;? (C++11 起)

  • 显示模板实例化声明
  • "C++",默认的语言链接。
  • "C",使得以 C 程序语言编写的函数进行链接,以及在 C++ 程序中定义能从 C 模块调用的函数成为可能。
  • 外部链接声明
  • 提供以不同程序语言编写的模块间的链接。

(1)

(2)

extern "C" {
??? int open(const char *pathname, int flags); // C 函数声明
}
?
int main()
{
??? int fd = open("test.txt", 0); // 从 C++ 程序调用 C 函数
}
?
// 此 C++ 函数能从 C 代码调用
extern "C" void handler(int) {
??? std::cout << "Callback invoked\n"; // 它能使用 C++
}

concept(C++20 )

约束与概念:

(1) 类模板,函数模板,以及非模板函数(常为类模板的成员),可以与约束(constraint)关联,它指定对模板实参的一些要求,这些要求可被用于选择最恰当的函数重载和模板特化。

(2) 这种要求的具名集合被称为概念(concept)。每个概念都是谓词,于编译时求值,并成为以之作为一项约束的模板接口的一部分:

?

const

说明:

用法

?

consteval(c++20)

说明:

  • consteval?- 指定函数是立即函数(immediate function),即每次调用该函数必须产生编译时常量。

?

?

consteval int sqr(int n) {

? return n*n;

}

constexpr int r = sqr(100);? // OK

int x = 100;

int r2 = sqr(x);? // 错误:调用不产生常量

constexpr(c++11)

说明:

constexpr 说明符声明 可以 在编译时求 得 函数 或变量的 值。 然后这些 变量和函数(若给定了合适的函数实参)即可用于仅允许编译时常量表达式之处。

constexpr?变量必须满足下列要求:

constexpr?函数必须满足下列要求:

  • 它必须非

(C++20 前)

(C++20 起)

(C++20 前)

(C++14 前)

(C++20 前)

(=default;?或?=delete;?的函数体不含任何上述内容。)

  • 非字面类型的变量定义
  • 静态或线程存储期变量的定义
  • 函数体必须含:
    • 拥有除?case?和?default?之外的标号的语句

(C++14 起)

函数体非?=delete;?的?constexpr?构造函数必须满足下列额外要求:

  • 对于?class 或 struct?的构造函数,每个子对象和每个非变体非 static 数据成员必须被初始化。若类是联合体式的类,对于其每个非空匿名联合体成员,必须恰好有一个变体成员被初始化
  • 对于非空?union?的构造函数,恰好有一个非静态数据成员被初始化

(C++20 前)

析构函数不能为?constexpr?,但能在常量表达式中调用平凡析构函数

(C++20 前)

函数体非?=delete;?的?constexpr?析构函数必须满足下列额外要求:

  • 每个用于销毁非静态数据成员与基类的析构函数必须为 constexpr 析构函数。

(C++20 起)

对于?constexpr?函数模板和类模板的?constexpr?函数成员,必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr,尽管常量表达式中不能出现这种函数的调用。

带初始化器的 if 语句

(1)

constexpr int factorial(int n)
{
??? return n <= 1? 1 : (n * factorial(n - 1));
}

(2)

template <typename T>
auto get_value(T t) {
??? if constexpr (std::is_pointer_v<T>)
??????? return *t; // 对 T = int* 推导返回类型为 int
??? else
??????? return t;? // 对 T = int 推导返回类型为 int
}

constinit(c++20)

说明: 说明符声明拥有静态或线程存储期的变量。

constinit 不能和 constexpr 或 consteval 一同使用。声明的变量为引用时, constinit 等价于 constexpr 。声明的变量为对象时, constexpr 强制对象必须拥有静态初始化和常量析构,并使对象有 const 限定,然而 constinit 不强制常量析构和 const 限定。

(1)初始化声明

const char *g() { return "dynamic initialization"; }
constexpr const char *f(bool p) { return p ? "constant initializer" : g(); }
?
constinit const char *c = f(true); // OK
// constinit const char *d = f(false); // 错误

(2)用于非初始化声明,以告知编译器 thread_local 变量已被初始化。

extern thread_local constinit int x;
int f() { return x; } // 无需检查防卫变量

const_cast见类型转换

dynamic_cast见类型转换

const_cast?<?新类型?>?(?表达式?)

dynamic_cast?<?新类型?>?(?表达式?)

?

?

alignas(c++11)

头文件:<stdalign.h> 与 <cstdalign>

说明:指定类型或对象的对齐要求。说明符可应用于变量或非位域类数据成员的

声明,或可应用于 class/struct/union 或枚举的定义。它不能应用于函数形参

或 catch 子句的异常形参。同一声明上,弱于其他 alignas 的有效的非零对齐被忽略。始终忽略 alignas(0)。

alignas( 表达式 ):必须是求值为零或合法的对齐或扩展对齐的整型常量表达式。

alignas( 类型标识 ):等价于 alignas(alignof(类型))

alignas( ... ):等价于对同一说明应用多个 alignas 说明符,逐个对应于形参包的各个成员,

形参包可以是类型或非类型形参包。

// sse_t 类型的每个对象将对齐到 16 字节边界
struct alignas(16) sse_t
{
? float sse_data[4];
};
// 数组 "cacheline" 将对齐到 128字节边界
alignas(128) char cacheline[128];

alignof 运算符(c++11)

头文件

说明:查询类型的对齐要求。该类型可以为完整对象类型、元素类型完整的数组类型或者到这些类型之一

的引用类型。若类型为引用类型,则运算符返回被引用类型的对齐;若类型为数组类型,

则返回元素类型的对齐要求。

alignof(?类型标识?):返回std::size_t类型的值

#include <iostream>

struct Foo {

??? int?? i;

??? float f;

??? char? c;

};

struct Empty {};

struct alignas(64) Empty64 {};

int main()

{

??? std::cout << "Alignment of"? "\n"?? "- char???????????? : " << alignof(char)??? << "\n"

??????? "- pointer????????? : " << alignof(int*)??? << "\n"

??????? "- class Foo??????? : " << alignof(Foo)???? << "\n"

??????? "- empty class????? : " << alignof(Empty)?? << "\n"

??????? "- alignas(64) Empty: " << alignof(Empty64) << "\n";

}

std::max_align_t(c++11)

头文件:<cstddef>

说明:std::max_align_t 通常是最大标量类型的同意词,在大多数平台上是 long

double ,而其对齐要求是 8 或 16 。

?

#include <iostream>
#include <cstddef>
int main()
{
??? std::cout << alignof(std::max_align_t) << '\n';
}

>> 16

and

and_eq

bitand

bitor

compl

not

not_eq

or

or_eq

xor

xor_eq

<%

%>

<:

:>

%:

%:%:

&&????????

&=????????

&????????

|????????

~????????

!????????

!=????????

||????????

|=????????

^????????

^=????????

{????????

}????????

[????????

]????????

#????????

##????????

if(n > 0 and n < 5)

value? and_eq data;

asm

说明:给予在 C++ 程序中嵌入汇编语言源代码的能力。

asm (?字符串字面量?)? 字符串字面量 通常是以汇编语言编写的短程序,每当执行这条声明时对其执行。

atomic_cancel (TM TS)

atomic_commit (TM TS)

atomic_noexcept (TM TS)

说明:

事务性内存(transactional memory是在事务中结合语句组的并发同步机制,事务具有:

原子性(atomic)(要么语句全部发生,要么全部不发生)

隔离性(isolated)(事务中的语句不会观察到另一事务写入一半,即使它们并行执行)

同步块synchronized 复合语句

(1)如同在一个全局锁下执行复合语句:程序中的所有最外层同步块都以一个单独的全序执行。

在该顺序中,每个同步块的结尾同步于(synchronize with)下个同步块的开始。内嵌于其

他同步块的同步块没有特殊语义。同步块不是事务(不同于后面的原子块),并可以调用事务不安全的函数。

(2)以任何方式(抵达结尾,执行 goto、break、continue 或 return,或抛出异常)离开同步块都会退出该块,

而若所退出的块是外层块,则这在单一全序中同步于下个同步块。

不允许用 goto 或 switch 进入同步块。

原子块:

atomic_noexcept 复合语句

atomic_cancel 复合语句

atomic_commit 复合语句

1) 若抛出异常,则调用 std::abort

2) 若抛出异常,则调用 std::abort,除非该异常是用于事务取消的异常之一(见后述),这种情况下事务被取消(cancel):程序中所有由该原子块的各操作的副作用所修改的内存位置的值,被还原到该原子块的执行开始时它们曾拥有的值,而异常照常持续栈回溯。

3) 若抛出异常,则正常地提交事务。

用于 atomic_cancel 块中的事务取消的异常有 std::bad_alloc、std::bad_array_new_length、std::bad_cast、std::bad_typeid、std::bad_exception、std::exception 和所有从它派生的标准库异常,以及特殊异常类型 std::tx_exception<T>。

不允许原子块中的 复合语句 执行任何非 transaction_safe 的表达式或语句,或调用非 transaction_safe 的函数(这是编译时错误)。

(4)以除异常之外的任何方式(抵达结尾、goto、break、continue、return)离开原子块时,将提交事务。若用 std::longjmp 退出原子块则行为未定义。

事务安全的函数:

可在函数声明中用关键词?transaction_safe?将其显式声明为事务安全。

(1)

#include <iostream>

#include <vector>

#include <thread>

int f()

{

??? static int i = 0;

??? synchronized { // 开始同步块

??????? std::cout << i << " -> ";

??????? ++i;?????? // 每次调用 f() 都获得 i 的唯一值

??????? std::cout << i << '\n';

??????? return i; // 结束同步块

??? }

}

int main()

{

??? std::vector<std::thread> v(10);

??? for(auto& t: v)

??????? t = std::thread([]{ for(int n = 0; n < 10; ++n) f(); });

??? for(auto& t: v)

??????? t.join();

}

>>>

0 -> 1

1 -> 2

2 -> 3

...

99 -> 100

(2)

// 每次调用 f() 都取得 i 的唯一值,即使以并行进行
int f()
{
?? static int i = 0;
?? atomic_noexcept { // 开始事务
//?? printf("before?%d\n", i); // 错误:不能调用非事务安全的函数
????? ++i;
????? return i; // 提交事务
?? }
}

auto

(1)类型推导C++11 起:

对于变量,指定要从其初始化器自动推导出其类型。

对于函数,指定要从其 return 语句推导出其返回类型。(C++14 起)

对于非类型模板形参,指定要从实参推导出其类型。(C++17 起)

(2):带尾随返回类型的函数声明:

尾随返回类型仅在最外层函数声明符中允许使用。此情况下的 声明说明符序列 必须包含关键词 auto

(3)结构化绑定声明

见:结构化绑定声明(c++17)

(1)

auto (1) (C++11 起)

decltype(auto) (2) (C++14 起)

类型制约?auto (3) (C++20 起)

类型制约?decltype(auto) (4) (C++20 起)

(2)

auto 说明符亦可用于后随尾随返回类型的函数声明符,该情况下返回类型为其尾随返回类型(它也可以是占位符类型):

auto (*p)() -> int; // 声明指向返回 int 的函数的指针

尾随返回类型,当返回类型取决于实参名时,例如 template <class T, class U> auto add(T t, U u) -> decltype(t + u);,或当返回类型复杂时,例如在 auto fpif(int)->int(*)(int) 中,尾随返回类型很有用

若函数声明的 声明说明符序列 包含关键词 auto,则尾随返回类型可以省略,而编译器将从 return 语句中所用的表达式的类型推导出它。若返回类型使用的不是 decltype(auto),则推导遵循模板实参推导的规则进行。

(1)

template<class T, class U>
auto add(T t, U u) { return t + u; } // 返回类型是 operator+(T, U) 的类型

(2)

// 在其所调用的函数返回引用的情况下

// 函数调用的完美转发必须用 decltype(auto)

template<class F, class... Args>

decltype(auto) PerfectForward(F fun, Args&&... args)

{

??? return fun(std::forward<Args>(args)...);

}

(3)

template<auto n> // C++17 auto 形参声明
auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能从花括号初始化器列表推导
{
??? return {n, n};
}

bool/break/switch/case/continue/switch/do/if/enum/false/for/goto

常规操作

char/char8_t(c++20)/char16_t(c++20)/char32_t(c++20)/double/float/int/long/short

?

default

用法

类名()?=?default?;

?

::(可选)????delete ???表达式

::(可选)????delete []?表达式

如果取代函数体而使用特殊语法?= delete?;,则该函数被定义为弃置的(deleted)。任何弃置函数的使用都是非良构的(程序无法编译)。

类名()?=?delete?;

try-catch

说明:将一或多个异常处理块(catch 子句)与复合语句关联。

语法

try?复合语句?处理块序列?? 其中?处理块序列?是一或多个?处理块?的序列,它有下列语法:

catch?(?attr(可选)?类型说明符序列?声明符?)?复合语句

(1)

catch?(?attr(可选)?类型说明符序列?抽象声明符(可选)?)?复合语句

(2)

catch?(?...?)?复合语句

(3)

?

?

协程:

协程是能暂停执行以在之后恢复的函数。协程是无栈的:它们通过返回到调用方暂停执行,并且从栈分离存储恢复所要求的数据。这允许编写异步执行的顺序代码(例如不使用显式的回调来处理非阻塞 I/O),还支持对惰性计算的无限序列上的算法及其他用途。

若函数的定义做下列任何内容之一,则它是协

co_wait(c++20)

  • ?co_await?运算符暂停执行,直至恢复

co_yield(c++20)

  • 用关键词?co_yield?暂停执行并返回一个值

co_return(c++20)

  • 用关键词?co_return?完成执行并返回一个值

?

decltype(c++11)

说明:在难以或不可能以标准写法进行声明的类型时,decltype 很有用,例如 lambda 相关类型或依赖于模板形参的类型。

语法

decltype (?实体?)

(1)

(C++11 起)

decltype (?表达式?)

(2)

(C++11 起)

(1) 若实参为无括号的标识表达式或无括号的类成员访问表达式,则 decltype 产生以此表达式命名的实体的类型。若无这种实体,或该实参指名某个重载函数,则程序非良构。

若实参是指名某个结构化绑定的无括号的标识表达式,则 decltype 产生被引用类型(在关于结构化绑定声明的说明中有所描述)。(C++17 起)

若实参是指名某个非类型模板形参的无括号的标识表达式,则 decltype 生成该模板形参的类型(当该模板形参以占位符类型声明时,则为进行任何所需的类型推导后的类型)。(C++20 起)

(2) 若实参是其他类型为 T 的任何表达式,且

a) 若 表达式 的值类别为亡值,则 decltype 产生 T&&;

b) 若 表达式 的值类别为左值,则 decltype 产生 T&;

c) 若 表达式 的值类别为纯右值,则 decltype 产生 T。

注意如果对象的名字带有括号,则它被当做通常的左值表达式,从而 decltype(x) decltype((x)) 通常是不同的类型。

decltype(auto)????? (C++14 起)

类型制约?decltype(auto)??? (C++20 起)

?

?

  • 占位类型说明符
  • 检查实体的声明类型,或表达式的类型和值类别。

#include <iostream>

struct A { double x; };

const A* a;

decltype(a->x) y;?????? // y 的类型是 double(其声明类型)

decltype((a->x)) z = y; // z 的类型是 const double&(左值表达式)

template<typename T, typename U>

auto add(T t, U u) -> decltype(t + u) // 返回类型依赖于模板形参

{???????????????????????????????????? // C++14 开始可以推导返回类型

??? return t+u;

}

enum

语法:

enum-关键词?attr(可选)?enum-(可选)?enum-(可选)(C++11)?{?枚举项列表(可选)?} (1)

enum-关键词?attr(可选)?enum-?enum-(可选)?;?? (2)(C++11 起)

?

enum-关键字

enumenum class(C++11 起)??enum struct(C++11 起)?之一

attr(C++11)

-

任意数量的属性的可选序列

enum-名

-

所声明的枚举的名字。若存在,且若此声明为重声明,则其之前可带有?嵌套名说明符(C++11 起),即名字和作用域解析运算符?::?的序列并以作用域解析运算符结尾。仅可在无作用域枚举声明中省略名字

enum-基(C++11)

-

冒号 (:),后随指名某个整型类型的?类型说明符序列(若它为 cv 限定,则忽略其限定性),该类型将作为此枚举类型的固定底层类型

枚举项列表

-

枚举项定义的逗号分隔列表,每项要么是简单的?标识符,它成为枚举项之名,要么是带初始化器的标识符:标识符?=?常量表达式

有两种截然不同的枚举:无作用域枚举(以?enum-关键词?enum?声明)和有作用域枚举(以?enum-关键词?enum class?或?enum struct?声明)。

  • 无作用域枚举

enum?名字?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?}

(1)

enum?名字?:?类型?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?}

(2)

(C++11 起)

enum?名字?:?类型?;

(3)

(C++11 起)

1)?声明无作用域枚举类型,其底层类型不固定(此情况中,底层类型是由实现定义的某个能表示所有枚举项值的整型类型;此类型不大于?int,除非枚举项的值不能放入?int?或?unsigned int。若?枚举项列表?为空,则底层类型为如同枚举拥有单个值为 0 的枚举项)。

2)?声明底层类型固定的无作用域枚举类型。

3)?无作用域枚举的不可见枚举声明必须指定底层类型。

每个?枚举项?都成为该枚举类型(即?名字)的一个具名常量,在其外围作用域可见,且可用于要求常量的任何位置。整数、浮点和枚举类型的值,可用?static_cast?或显式转型转换到任何枚举类型。

无作用域枚举的?名字?可以忽略:这种声明仅将各枚举项引入到其外围作用域中:

  • 有作用域枚举

enum?struct|class?名字?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?}

(1)

enum?struct|class?名字?:?类型?{?枚举项?=?常量表达式?,?枚举项?=?常量表达式?,?...?}

(2)

enum?struct|class?名字?;

(3)

enum?struct|class?名字?:?类型?;

(4)

1)?声明底层类型为?int?的有作用域枚举类型(关键词?class?与?struct?完全等价)

2)?声明底层类型为?类型?的有作用域枚举类型

3)?底层类型为?int?的有作用域枚举类型的不可见枚举声明

4)?底层类型为?类型?的有作用域枚举类型的不可见枚举声明

每个?枚举项?都成为该枚举的类型(即?名字)的具名常量,它为该枚举的作用域所包含,且可用作用域解析运算符访问。没有从有作用域枚举项到整数类型的隐式转换,尽管?static_cast?可用于获得枚举项的数值。

  • using enum 声明

using?enum?嵌套名说明符(可选)?名字?;

(C++20 起)

using enum 声明引入其所指名的枚举的枚举项名字,如同用对每个枚举项的?using 声明。在类作用域中时, using enum 声明将其所指名的枚举的枚举项名字作为成员添加到作用域,使成员查找能访问它们

?

(1)无作用域枚举

enum access_t { read = 1, write = 2, exec = 4 }; //枚举项:1、2、4 范围:0..7
access_t rwe = static_cast<access_t>(7);
assert((rwe & read) && (rwe & write) && (rwe & exec));
?
access_t x = static_cast<access_t>(8.0); // C++17 起为未定义行为
access_t y = static_cast<access_t>(8); // C++17 起为未定义行为
?
enum foo { a = 0, b = UINT_MAX }; // 范围:[0, UINT_MAX]
foo x= foo(-1); // C++17 起为未定义行为,即使 foo 的底层类型为 unsigned int

(2)有作用域枚举

enum class Color { red, green = 20, blue };
Color r = Color::blue;
switch(r)
{
??? case Color::red? : std::cout << "red\n";?? break;
??? case Color::green: std::cout << "green\n"; break;
??? case Color::blue : std::cout << "blue\n";? break;
}
// int n = r; // 错误:不存在从有作用域枚举到 int 的转换
int n = static_cast<int>(r); // OK, n = 21

enum byte : unsigned char {}; // byte 是新的整数类型
byte b { 42 }; // C++17 起 OK(直接列表初始化)

(3)using enum 声明

enum class fruit { orange, apple };
struct S {
? using enum fruit; // OK :引入 orange 与 apple 到 S 中
};
void f()
{
??? S s;
??? s.orange;? // OK :指名 fruit::orange
??? S::orange; // OK :指名 fruit::orange
}

?

?

?<type_traits>

template<?class?T?>

struct?is_trivially_copyable;

trivally copyable 需要满足3个条件:

  1. 连续的内存空间
  2. 拷贝构造函数需要拷贝全部的bits (memcpy)
  3. 没有虚函数和 noexcept constructor

std::alignment_of(c++11)

std::alignment_of_v (C++17 )

提供等于 T 类型对齐要求的成员常量 value ,如同用 alignof 表达式获得。

#include <iostream>
#include <type_traits>
?
class A {};
?
int main()
{
??? std::cout << std::alignment_of<A>::value << '\n';
??? std::cout << std::alignment_of<int>() << '\n'; // 另一种语法
??? std::cout << std::alignment_of_v<double> << '\n'; // c++17 另一种语法
}

?

?

?

std::remove_all_extents_t<T>

?

<ctime>

?

volatile

?

size_t

?

is_trivial

?

Explicit

?

override

?

snprintf

?

calloc

?

strdup

?

sqrt

?

Std::log

?

Math_errhandling

?

Volatile

?

wchar

?

Char32_t

?

Char16_t

?

.h/.hpp/.hxx

?

noexcept

noexcept(false)

Numeric_limit

?

epsilon

?

Initializer_list

?

stack

?

final

?

For_each

?

algorithm

?

throw

throw std::runtime_error( "File cannot be opened")

?

std::invalid_argument

logic_error

bad_typeid

?

bad_cast

?

bad_array_new_length

?

bad_alloc

?

std::system_error

?

bad_exception

?

std::out_of_range

?

std::exception

?

throw(std::runtime_error)

?

std::terminate()

?

std::is_nothrow_move_constructible

?

std::atexit

?

?std::at_quick_exit

Logic_error

?

mutable

?

lambda

?

decltype

?

typeid

?

copy

?

sort

?

transform

?

Make_shared

?

move

?

Forward(cv)

?

Lock_guard

?

<mutex>

?

constexpr

?

Static_assert

?

defaule

?

register

?

Thread_local

?

inline

?

using

?

typename

?

template

?

asm

?

posix

?

is_arithmetic

?

[[noreturn]]

?

dlsym

?

拖尾返回类型->type

?

左右值引用

?

accumulate

?

Chrono::

Seconds

System_clock

Time_point

?

utility

?

Is_copy

?

智能指针

std::unique_ptr

类型的移动构造,移动赋值,"转换"移动构造和"转换"移动赋值

td::make_unique<A[]>(10)

const_iterator

?

std::shared_ptr

?

std::weak_ptr

?

std::basic_ios类型的std::move()

?

std::basic_filebuf

多线程

std::thread

?

std::unique_lock

?

std::shared_lock

?

std::promise

?

std::future

?

std::shared_future

?

std::packaged_task

?

std::is_copy_constructible

?

std::is_trivially_move_constructible

?

std::is_trivially_copy_assignable

?

std::is_trivially_move_assignable

重载

operator delete

?

编译宏

#define subs(x) a ## x???????? //合规

?

#define A(x) #x ????????// 合规

?

defined, __LINE__, __FILE__, __DATE__, __TIME__, __STDC__, errno 和assert。

不能使用setjmp宏和longjmp函数。

<cstring>

<clocale> (locale.h)setlocale函数

std::hash

std::new_handler

offsetof

Placement new

std::bind

<cctype>

isdigit和isxdigit

<algorithm>

<cstdint>

const_iterator

equal_range

std::distance

<random>

std::srand(std::time(nullptr))

std::random_device rd;

????????std::default_random_engine eng{ rd() };

????????std::uniform_int_distribution<int> ud{ 0, 100 };

?

<cstdio>

fgetpos, fopen, ftell, gets, perror, remove, rename

basic_filebuf<charT, traits>

fstream

fseek、fsetpos或rewind

结构化绑定声明(c++17)

说明

类似引用,结构化绑定是既存对象的别名。不同于引用的是,结构化绑定的类型不必为引用类型。

结构化绑定声明将 标识符列表 中的所有标识符,引入作为其外围作用域中的名字,并将它们绑定到

表达式 所指代的对象的各个子对象或元素。以此方式引入的绑定被称作结构化绑定。

attr(可选)?cv-auto?ref-运算符(可选)?[?标识符列表?]?=?表达式?;(1)

attr(可选)?cv-auto?ref-运算符(可选)?[?标识符列表?]?{?表达式?}?;(2)

attr(可选)?cv-auto?ref-运算符(可选)?[?标识符列表?]?(?表达式?)?;(3)

说明:

attr

-

任意数量的属性的序列

cv-auto

-

可有 cv 限定的?auto?类型说明符,亦可包含存储类说明符?static?或?thread_local?;在 cv 限定符中包含 volatile 是被弃用的?(C++20 )

ref-运算符

-

&?或?&&?之一

标识符表

-

此声明所引入的各标识符的逗号分隔的列表

表达式

-

顶层没有逗号运算符的表达式(文法上为赋值表达式),且具有数组或非联合类之一的类型。

情况 1:绑定数组

标识符列表?中的每个标识符均成为指代数组的对应元素的左值。标识符的数量必须等于数组的元素数量。

int a[2] = {1,2};

auto [x,y] = a; // 创建 e[2],复制 a 到 e,然后 x 指代 e[0],y 指代 e[1]

auto& [xr, yr] = a; // xr 指代 a[0],yr 指代 a[1]

情况 2:绑定元组式类型

表达式 std::tuple_size<E>::value 必须是良构的整数常量表达式,且标识符的数量必须等于 std::tuple_size<E>::value。

示例:

float x{};

char? y{};

int?? z{};

std::tuple<float&,char&&,int> tpl(x,std::move(y),z);

const auto& [a,b,c] = tpl;

// a 指名指代 x 的结构化绑定;decltype(a) 为 float&

// b 指名指代 y 的结构化绑定;decltype(b) 为 char&&

// c 指名指代 tpl 的第 3 元素的结构化绑定;decltype(c) 为 const int

情况 3:绑定到数据成员

struct S {

??? int x1 : 2;

??? volatile double y1;

};

S f();

const auto [x, y] = f(); // x 是标识 2 位位域的 const int 左值

???????????????????????? // y 是 const volatile double 左值

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-14 20:56:33  更:2022-02-14 20:58:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:03:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码