Abseil 源码阅读笔记·容器 [0x02]

FixedArray

先从简单的开始,看一下 FixedArray,学一点工程技巧。

注释里的介绍:

1
2
3
4
5
6
7
8
9
10
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
// the array can be determined at run-time. It is a good replacement for
// non-standard and deprecated uses of `alloca()` and variable length arrays
// within the GCC extension. (See
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
//
// `FixedArray` allocates small arrays inline, keeping performance fast by
// avoiding heap operations. It also helps reduce the chances of
// accidentally overflowing your stack if large input is passed to
// your function.

来看一下代码,起手一个命名空间 absl,紧跟一个宏 ABSL_NAMESPACE_BEGIN,展开后是 inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {,一个内联的命名空间,这是用来控制版本的,在外部使用时不需要指定内联命名空间的名字,但是在编译后是有相关的符号的。

1
2
template <typename T, size_t N = kFixedArrayUseDefault,
typename A = std::allocator<T>>

FixedArray 是一个模板类,有三个模板参数,T 代表类型,N 代表要内联的元素个数,A 是个 allocator。当 N 不指定时,会使用 kFixedArrayUseDefault 作为默认参数,而在上面已经定义了:

1
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);

这实际上是 size_t 的最大值,正常使用时不会想着要内联这么多的东西,由此可以判断使用者有没有指定一个 N,如果没有指定那就使用默认值(默认最多内联 256 bytes 的内容),如果指定了再用指定的元素个数 N。注释里也提到了,大多数情况不需要指定 N

1
2
3
static constexpr size_type inline_elements =
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
: static_cast<size_type>(N));

类的开头是一个断言,确保 T 不是 C 风格数组,或者大小已知。这是为了防止类似 int [] 的东西被传进来,它的大小不确定,不能用于创建固定大小的 FixedArray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static constexpr size_t kInlineBytesDefault = 256;

using AllocatorTraits = std::allocator_traits<A>;
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
// but this seems to be mostly pedantic.
template <typename Iterator>
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>::value>;
static constexpr bool NoexceptCopyable() {
return std::is_nothrow_copy_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool NoexceptMovable() {
return std::is_nothrow_move_constructible<StorageElement>::value &&
absl::allocator_is_nothrow<allocator_type>::value;
}
static constexpr bool DefaultConstructorIsNonTrivial() {
return !absl::is_trivially_default_constructible<StorageElement>::value;
}

接下来定义了几个东西,一个是 kInlineBytesDefault 内联的默认最大大小,还有一个 EnableIfForwardIterator,似乎是出于工程上的妥协,就不去管它了,还有三个判断函数,功能也很显然。

后面又有一些 using,具体见代码,就不再赘述了。

这类有一大堆构造函数之类的,也不详细讲了。


Abseil 源码阅读笔记·容器 [0x02]
http://xiao-h.com/2025/01/22/Abseil-0x02-容器/
作者
小H
发布于
2025年1月22日
许可协议