需要记忆的(面试六脉神剑)
__has_include
execution
memory_resource
缓存线接口
scoped_lock
optional
核心语言特性
- UTF-8字符文字
u8'c-char '
- constexpr可以放在编译期用作条件判断
{
init_statement
attr(optional) if constexpr(optional) ( condition )
statement-true
else
statement-false
}
- lambda表达式会默认尝试转换为constexpr
auto Fwd = [](int(*fp)(int), auto a){ return fp(a); };
auto C = [](auto a){ return a; };
static_assert(Fwd(C, 3) == 3); // OK
auto NC = [](auto a){ static int s; return a; };
static_assert(Fwd(NC, 3) == 3); // error: no specialization can be
// constexpr because of static s
- 变量可以用inline修饰
变量被多个源文件外部链接必须是inline,inline修饰的作用类似于宏替换constexpr
// variable with external linkage included in multiple source files must be inline
inline std::atomic<int> counter(0);
- 结构化绑定声明
将指定的名称绑定到初始化式的子对象或元素。
int a[2] = {1, 2};
auto [x, y] = a; // creates e[2], copies a into e,
// then x refers to e[0], y refers to e[1]
auto& [xr, yr] = a; // xr refers to a[0], yr refers to a[1]
- if和switch可以初始化参数
if (auto it = m.find(10); it != m.end()) { return it->second.size(); }
- 临时实例化
任何完整类型T的prvalue都可以转换为相同类型T的xvalue。这种转换通过以临时对象作为结果对象对prvalue求值来初始化一个T类型的临时对象,并生成一个表示临时对象的xvalue。如果T是类类型的类或数组,则它必须具有可访问且不可删除的析构函数。
struct S { int m; };
int i = S().m; // member access expects glvalue as of C++17;
// S() prvalue is converted to xvalue
- 折叠表达式
(E op ...)等价于(E1 op (... op (EN-1 op EN)))
(…op E)等价于(((E1 op E2) op…)op EN)
(E op…op I)等价于(E1 op (... op (EN−1 op (EN op I))))
(I op ... op E)等价于((((I op E1) op E2) op ...) op EN)
template<typename... Args>
void printer(Args&&... args)
{
(std::cout << ... << args) << '\n';
}
int main()
{
printer(1, 2, 3, "abc");
}
- auto声明非类型模版参数
template<auto n>
struct B { /* ... */ };
B<5> b1; // OK: non-type template parameter type is int
B<'a'> b2; // OK: non-type template parameter type is char
B<2.5> b3; // error (until C++20): non-type template parameter type cannot be double
- __has_include
检查头文件或源文件是否可用。
#if __has_include(<optional>)
# include <optional>
# define has_optional 1
template<class T> using optional_t = std::optional<T>;
#elif __has_include(<experimental/optional>)
# include <experimental/optional>
# define has_optional -1
template<class T> using optional_t = std::experimental::optional<T>;
#else
# define has_optional 0
# include <utility>
- any
类any描述了用于任何复制构造类型的单个值的类型安全容器。
// any type
std::any a = 1;
std::cout << a.type().name() << ": " << std::any_cast<int>(a) << '\n';
a = 3.14;
std::cout << a.type().name() << ": " << std::any_cast<double>(a) << '\n';
a = true;
std::cout << a.type().name() << ": " << std::any_cast<bool>(a) << '\n';
- excution
用作消除并行算法重载歧义的唯一类型,可以选择执行策略类型:sequenced_policy(顺序执行),parallel_policy(并行执行),parallel_unsequenced_policy(非顺序并行执行)。
int x = 0;
std::mutex m;
int a[] = {1,2};
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) {
std::lock_guard<std::mutex> guard(m);
++x; // correct
});
- filesystem
filesystem库提供了对文件系统及其组件(如路径、常规文件和目录)执行操作的工具。
- std::pmr::memory_resource
封装内存资源的类的抽象接口
派生出:
synchronized_pool_resource(线程安全),
unsynchronized_pool_resource(线程不安全),
monotonic_buffer_resource(特殊用途:用于非常快速的内存分配,在这种情况下,内存用于构建几个对象,然后立即释放所有内存。)
- optional
选择性保存一个对象的包装器
// std::nullopt can be used to create any (empty) std::optional
auto create2(bool b) {
return b ? std::optional<std::string>{"Godzilla"} : std::nullopt;
}
- variant
类型安全的有区别的union
std::variant<int, float> v, w;
v = 42; // v contains int
int i = std::get<int>(v);
assert(42 == i); // succeeds
w = std::get<int>(v);
w = std::get<0>(v); // same effect as the previous line
w = v; // same effect as the previous line
// std::get<double>(v); // error: no double in [int, float]
// std::get<3>(v); // error: valid index values are 0 and 1
try {
std::get<float>(w); // w contains int, not float: will throw
}
catch (const std::bad_variant_access& ex) {
std::cout << ex.what() << '\n';
}
标准库特性
- weak_from_this
返回一个std::weak_ptr<T>,通过所有引用this的现有std::shared_ptr跟踪this的所有权
这是private mutable weak_ptr成员的副本,该成员是enable_shared_from_this的一部分。
- owner_less
这个函数对象为std::weak_ptr和std::shared_ptr提供了基于所有者的(而不是基于值的)混合类型排序。只有当两个智能指针都为空或共享所有权时,才会比较等效,即使get()获得的原始指针的值不同(例如,当它们指向同一对象中的不同子对象)。
#include <iostream>
#include <memory>
#include <set>
int main () {
int * p = new int (10);
std::shared_ptr<int> a (new int (20));
std::shared_ptr<int> b (a,p);
std::set < std::shared_ptr<int> > value_based;
std::set < std::shared_ptr<int>, std::owner_less<std::shared_ptr<int>> > owner_based;
value_based.insert (a);
value_based.insert (b);
owner_based.insert (a);
owner_based.insert (b);
std::cout << "value_based.size() is " << value_based.size() << '\n';
std::cout << "owner_based.size() is " << owner_based.size() << '\n';
delete p;
return 0;
}
/*输出
value_based.size() is 2
owner_based.size() is 1
*/
- shared_ptr支持数组
#include <cstddef>
#include <memory>
#include <iostream>
int main() {
const std::size_t arr_size = 10;
std::shared_ptr<int[]> pis(new int[10]{0,1,2,3,4,5,6,7,8,9});
for (std::size_t i = 0; i < arr_size; i++){
std::cout << pis[i] << ' ';
}
}
- byte
byte是一种独特的类型,它实现了c++语言定义中指定的字节概念。
- conjunction
判断类型是否一致
#include <iostream>
#include <type_traits>
// func is enabled if all Ts... have the same type as T
template<typename T, typename... Ts>
std::enable_if_t<std::conjunction_v<std::is_same<T, Ts>...>>
func(T, Ts...)
{
std::cout << "all types in pack are T\n";
}
- is_swappable
检查是否可交换
- is_invocable
检查函数和参数是否匹配
- is_aggregate
判断是否是数组
- clamp
template<class T>
constexpr const T& clamp( const T& v, const T& lo, const T& hi );
如果v < lo,返回lo。如果hi小于v,返回hi。其他情况下返回v。
- reduce
求和,可以并行计算(std::execution::par)
- inclusive_scan
扫描得到前面元素的累加或累乘值
- exclude_scan
扫描得到前面元素的累加或累乘值,需设置初始值,并且最后一个元素不参与计算。
#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector data {3, 1, 4, 1, 5, 9, 2, 6};
std::cout << "exclusive sum: ";
std::exclusive_scan(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, " "),
0);
std::cout << "\ninclusive sum: ";
std::inclusive_scan(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << "\n\nexclusive product: ";
std::exclusive_scan(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, " "),
1, std::multiplies<>{});
std::cout << "\ninclusive product: ";
std::inclusive_scan(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, " "),
std::multiplies<>{});
}
/*输出
exclusive sum: 0 3 4 8 9 14 23 25
inclusive sum: 3 4 8 9 14 23 25 31
exclusive product: 1 3 3 12 12 60 540 1080
inclusive product: 3 3 12 12 60 540 1080 6480
*/
- gcd
求最大公因数
- lcm
求最小公倍数
- extract
可用于在不重新分配的情况下修改map/set的key值。
- merge
用于合并map/set,如果元素的key在新容器已存在,则保留该元素,否则将其插入到新容器中,旧容器不再保留该元素。
#include <map>
#include <iostream>
#include <string>
int main()
{
std::map<int, std::string> ma {{1, "apple"}, {5, "pear"}, {10, "banana"}};
std::map<int, std::string> mb {{2, "zorro"}, {4, "batman"}, {5, "X"}, {8, "alpaca"}};
std::map<int, std::string> u;
u.merge(ma);
std::cout << "ma.size(): " << ma.size() << '\n';
u.merge(mb);
std::cout << "mb.size(): " << mb.size() << '\n';
std::cout << "mb.at(5): " << mb.at(5) << '\n';
for(auto const &kv: u)
std::cout << kv.first << ", " << kv.second << '\n';
}
/*输出
ma.size(): 0
mb.size(): 1
mb.at(5): X
1, apple
2, zorro
4, batman
5, pear
8, alpaca
10, banana
*/
- try_emplace
如果容器中没有具有该键的元素,则插入一个带有键k和值的新元素到容器中。
- insert_or_assign
如果容器中已经存在一个等价于k的键,则将std::forward<M>(obj)赋值给与键k对应的mapped_type。如果键不存在,则像通过insert一样插入新值,从value_type(k, std::forward<M>(obj))构造它。
- 连续迭代器(LegacyContiguousIterator)
不仅逻辑上连续,在物理上也连续。
- hypot支持3D
获取3D向量的长度。
- 缓存线接口
hardware_destructive_interference_size
hardware_constructive_interference_size
这些常量提供了一种可移植的方式来访问L1数据缓存线大小。
- uncaught_exceptions
检测当前线程中有多少异常已经抛出或重新抛出,但尚未输入匹配的catch子句。
- atomic<T>::is_always_lock_free
如果此原子类型总是无锁,则为true;如果从不或有时无锁,则为false。
- scoped_lock
类scoped_lock是一个互斥锁包装器,它提供了一种方便的RAII风格的机制,用于在作用域块期间拥有零个或多个互斥锁。