Reference:
Implement the C++ Standard Library: Design, Optimisations, Testing while Implementing Libc++
[C++] Object Lifetimes reading minute
1)
1) tail padding.
2) if type is empty, it does not acquire address.
e.g.
struct Foo {
int a;
char c;
bool b;
};
enum class ErrCode : int {
E1, E2, E3,
};
template*<typename Val, Err>
struct Expected {
union U {
[[no_unique_address]] Val val_;
[[no_unique_address]] Err err_;
};
[[no_unique_address]] U value_;
bool has_value_;
};
Without `no_unique_address`, no tail padding, sizeof(Expected<Foo, ErrCode>) == 12
bool has_value_;
can sneak into
U if U is of type Foo, `has_value_` would occupy Foo's tail padding,
thus:
sizeof(Expected<Foo, ErrCode>) == 8
U if U is of type Foo, `has_value_` would occupy Foo's tail padding,
thus:
sizeof(Expected<Foo, ErrCode>) == 8
2)
template<typename Val, Err>
struct Expected {
union U {
[[no_unique_address]] Val val_;
[[no_unique_address]] Err err_;
};
[[no_unique_address]] U value_;
bool has_value_;
Expected(const Expected& other) :
has_value{other.has_value} {
if (has_value_) {
std::construct_at(std::addressof(value_.val_), other.value_.val_);
} else {
std::construct_at(std::addressof(value_.err_), other.value_.err_);
}
}
};
Expected e1 = {Foo{}};
Expected e2 = e1;
assert(e2.has_value_); // Failed.
Why failed? Due to std::construct_at construct the value_ union's val_ and zero out the padding, which has_value_ resides in due to `no_unique_address`.
Take away:
Don't mix no_unique_address with manual lifetime management(union, construct_at, placement-new, std::bit_cast, std::start_lifetime_as, std::start_lifetime_as_array).
3)
Reference:Segmented Iterators and Hierarchical Algorithms - Matthew H. Austern
https://lafstern.org/matt/segmented.pdf
Which is faster?
std::deque<int> d = ...
// 1
for (int& i : d) {
i = std::clamp(i, 200, 500);
}
// 2 Faster due to using Segmented Iterators
std::ranges::for_each(d, [](int& i) {
i = std::clamp(i, 200, 500);
});
Segmented Iterators:
template <class T> struct seg_array_iter
{
// Local Iterator: position within the current segment (e.g., a vector<T>::iterator)
vector<T>::iterator cur;
// Segment Iterator: position among the segments (e.g., a vector<vector<T>*>::iterator)
vector<vector<T>*>::iterator node;
T& operator*() const { return *cur; }
seg_array_iter& operator++() {
// Standard increment: move to the next element in the current segment
if (++cur == (**node).end()) {
// End of segment reached: move to the next segment
++node;
// Set the local iterator (cur) to the beginning of the new segment
// or 0 (a null pointer equivalent for iterators) if it's the end.
cur = *node ? (**node).begin() : 0;
}
return *this;
}
// ... other iterator operations like operator==, operator!=, etc.
};
template <class Iter, class T>
inline void fill (Iter first, Iter last, const T& x)
{
typedef segmented_iterator_traits<Iter> Traits;
// Dispatch call: The compiler chooses the segmented or nonsegmented helper
// based on the type of Traits::is_segmented_iterator (true_type or false_type).
fill(first, last, x,
typename Traits::is_segmented_iterator());
}
template <class SegIter, class T>
void fill (SegIter first, SegIter last, const T& x, true_type)
{
typedef segmented_iterator_traits<SegIter> traits;
// Decompose the full segmented iterators into segment and local iterators
typename traits::segment_iterator sfirst = traits::segment (first);
typename traits::segment_iterator slast = traits::segment (last);
if (sfirst == slast) {
// Case 1: Start and end are in the same segment. Use one local fill.
fill(traits::local (first), traits::local (last), x);
} else {
// Case 2: Fill the *rest* of the starting segment
fill(traits::local (first), traits::end(sfirst), x);
// Case 3: Loop through all *middle* segments, filling them completely
for (++sfirst; sfirst != slast; ++sfirst)
fill(traits::begin(sfirst), traits::end(sfirst), x);
// Case 4: Fill the *start* of the ending segment (sfirst now equals slast)
fill(traits::begin(sfirst), traits::local (last), x);
}
} Take away:
- Use the most precise API for what you're trying to achieve.
- insert_range instead of insert in a loop. (O(n) vs. N * log(M) )
- use sorted_unique if the inputs are already sorted.
- Use library facilities (e.g. views::zip) to benefit from concept-based optimizations.
4)
compiler flag-Xclang -verify used for static_asserts
e.g.
clang++ -Xclang -verify -fsyntax-only test_integer_only.cpp
#include <type_traits>
template <typename T>
void strict_int_check() {
static_assert(std::is_integral<T>::value, "Type must be an integer!");
}
void test() {
// This line is valid, so no comment needed.
strict_int_check<int>();
// We WANT this line to fail.
// Without -verify, this breaks the build.
// With -verify, Clang checks if the error matches the regex in {{...}}.
strict_int_check<double>(); // expected-error {{Type must be an integer!}}
}