从reddit/hackernews/lobsters/meetingcpp摘抄一些c++动态。
每周更新
欢迎投稿,推荐或自荐文章/软件/资源等,请提交 issue
这个标签两个作用,1,直接干掉空基类优化,直接看官方例子https://eel.is/c++draft/dcl.attr.nouniqueaddr
template<typename Key, typename Value,
typename Hash, typename Pred, typename Allocator>
class hash_map {
[[no_unique_address]] Hash hasher;
[[no_unique_address]] Pred pred;
[[no_unique_address]] Allocator alloc;
Bucket *buckets;
// ...
public:
// ...
};
如果hash pred allocator都是空的,那和bucket共享同一个地址
第二个例子 https://godbolt.org/z/3r8hq5sxe
看傻了,居然只占1byte
#include <cassert>
#include <cstdint>
#include <algorithm>
#include <type_traits>
template<auto Size>
struct fixed_string {
char data[Size + 1]{};
static constexpr auto size = Size;
constexpr explicit(false) fixed_string(char const* str) { std::copy_n(str, Size + 1, data); }
constexpr explicit(false) operator std::string_view() const { return {data, Size}; }
};
template<auto Size> fixed_string(char const (&)[Size]) -> fixed_string<Size - 1>;
template<class T, fixed_string Str, auto Offset = 0>
struct field {
constexpr const auto& get() const { return *reinterpret_cast<const T*>(reinterpret_cast<const char*>(this) + Offset); }
constexpr operator const T&() const { return get(); }
};
enum class side : std::uint8_t { buy, sell };
struct trade {
[[no_unique_address]] field<::std::int32_t, "price"> price;
[[no_unique_address]] field<::std::uint32_t, "size", sizeof(std::int32_t)> quantity;
[[no_unique_address]] field<::side, "side", sizeof(std::int32_t) + sizeof(std::uint32_t)> side;
};
static_assert(1 == sizeof(trade));
auto parse(const void* msg) {
const auto& trade = *reinterpret_cast<const ::trade*>(msg);
assert(42 == trade.price);
assert(100 == trade.quantity);
assert(side::sell == trade.side);
}
int main() {
struct [[gnu::packed]] {
::std::int32_t price{42};
::std::uint32_t quantity{100};
::side side{side::sell};
} trade{};
parse(std::addressof(trade));
}
但实际上trade类不是用来初始化的,是靠trade当做一个轻量的带类型的盒子,来解析POD类型,这和POD指针有啥区别?栈空间也不用省啊
介绍futex_wait以及google补丁的提升,不过并没有合进内核
一个汇编教程,挺简单,这里直接总结下
基本语法
堆操作
push value ; pushes a value into the stack (decrements ESP by 4, the size of one stack ‘unit’).
pop register ; pops a value to a register (increments ESP by 4).
数据赋值
mov destination, source ; moves copies a value from/to a register.
mov destination, [expression] ; copies a value from a memory address resolved from a ‘register expression’ (single register or arithmetic expression involving one or more registers) into a register.
控制流
jmp destination ; jumps into a code location (sets EIP (instruction pointer)).
jz/je destination ; jumps into a code location if ZF (the zero flag) is set.
jnz/jne destination ; jumps into a code location if ZF is not set.
操作
cmp operand1, operand2 ; compares the 2 operands and sets ZF if they’re equal.
add operand1, operand2 ; operand1 += operand2;
sub operand1, operand2 ; operand1 -= operand2;
函数转移
call function ; calls a function (pushes current EIP, then jumps to the function).
retn ; returns to caller function (pops back the previous EIP).
汇编模式
函数开头
55 push ebp ; preserve caller function's base pointer in stack
8B EC mov ebp, esp ; caller function's stack pointer becomes base pointer (new stack frame)
83 EC XX sub esp, X ; adjust the stack pointer by X bytes to reserve space for local variables
函数结尾
8B E5 mov esp, ebp ; restore caller function's stack pointer (current base pointer)
5D pop ebp ; restore base pointer from the stack
C3 retn ; return to caller function
函数调用func(1, 2, 3);
6A 03 push 3
6A 02 push 2
6A 01 push 1
E8 XX XX XX XX call func
下面开始组合
if语句
void print_equal(int a, int b) {
if (a == b) {
printf("equal");
}
else {
printf("nah");
}
}
void __cdecl print_equal(int, int):
10000000 55 push ebp
10000001 8B EC mov ebp, esp
10000003 8B 45 08 mov eax, [ebp+8] ; load 1st argument
10000006 3B 45 0C cmp eax, [ebp+0Ch] ; compare it with 2nd
┌┅ 10000009 75 0F jnz short loc_1000001A ; jump if not equal
┊ 1000000B 68 94 67 00 10 push offset aEqual ; "equal"
┊ 10000010 E8 DB F8 FF FF call _printf
┊ 10000015 83 C4 04 add esp, 4
┌─┊─ 10000018 EB 0D jmp short loc_10000027
│ ┊
│ └ loc_1000001A:
│ 1000001A 68 9C 67 00 10 push offset aNah ; "nah"
│ 1000001F E8 CC F8 FF FF call _printf
│ 10000024 83 C4 04 add esp, 4
│
└── loc_10000027:
10000027 5D pop ebp
10000028 C3 retn
用宏来元编程的。不能细看,脑壳疼,有喜欢的,仓库在这里
这个文章从一个简单的算法开始,介绍各种库的api设计
// [[pre: alpha >= -1. && alpha <= 1. ]]
// [[pre: 11 <= beta && beta < 247 ]]
// [[post ret: ret >= 0. && ret <= 1.]]
auto noise(
float input,
float alpha,
int beta)
{
// set of extremely complex operations involving the inputs to the algorithm
return std::fmod(std::pow(input, alpha), float(beta)) / beta;
}
这个算法这些参数就很难用,首先类型就很模糊,弄错参数 位置可能结果就完全不一样
在考虑各种api调用交互,可能更不好用,
// noise.hpp
#pragma once
struct noise
{
float alpha;
int beta;
/* constexpr_in_some_future_standard */
float operator()(float input) const
{
return std::fmod(std::pow(input, alpha), float(beta)) / beta;
}
};
首先让noise输入简单一点,然后考虑引入反射。比较复杂,但是点子比较新颖。
复习一下函数指针以及对应的汇编
#include <iostream>
struct greater {
bool operator()(int a, int b) {
return a > b;
}
};
int main() {
struct greater obj;
std::cout << obj(3, 4);
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
lea rax, [rbp-1]
mov edx, 4
mov esi, 3
mov rdi, rax
call greater::operator()(int, int)
movzx eax, al
mov esi, eax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(bool)
mov eax, 0
leave
ret
激进一点 call都可以优化掉
这里讲c++17的一个特性
这段代码在c++17遍不过
template<typename Derived>
struct Base
{
private:
Base(){};
//friend int main(); //加上这行就能编译过
};
struct Derived : Base<Derived>
{
};
int main()
{
Derived d{};
//Derived d; //或者去掉大括号也能编译过
}
主要是触发了这个Extened Aggergate Initialisation
struct X
{
int a;
int b;
int c;
};
struct Y : X
{
int d;
};
//可以这样构造
Y y{1, 2, 3, 4};
//还可以这样
Y y{ {1, 2, 3}, 4};
//还可以这样
Y y{ {}, 4 };
//还可以这样
Y y{ {1}, 4};
//不可以这样
Y y{4};
上面编译不过的代码隐含的调用了基类构造,但是是private的,要么去掉括号避免,要么加上friend让构造可见
从他的一个小项目入手,怎么提高代码速度。没仔细看
还是介绍他的colony库,优化过的vector类似的容器。16年就在宣传