C++ 实用工具、容器扩展与标准库实现
1. Boost 中的循环缓冲区类
在 C++ 编程中,Boost 提供了一个经过优化的循环缓冲区类(
circular_buffer
),它支持迭代器且符合 STL 标准。使用这个类非常简单,以下是一个示例代码:
typedef circular_buffer<std::uint8_t, 4U> buffer_type;
void do_something()
{
buffer_type buffer;
// Put three bytes into the buffer.
buffer.in(1U);
buffer.in(2U);
buffer.in(3U);
// The size of the buffer is 3.
const buffer_type::size_type count = buffer.size();
// The buffer is not empty.
const bool is_empty = buffer.empty();
// Extract the first element.
const buffer_type::value_type value = buffer.out();
// The size of the buffer is now 2.
count = buffer.size();
}
上述代码展示了如何使用
circular_buffer
类进行数据的插入和提取操作。
2. Boost 库概述
Boost 库是一个庞大的通用工具集合,面向广泛的 C++ 用户和应用领域。它扩展了 C++ 语言规范之外的功能,包含许多独立的库,如通用工具库、数值和词法操作库、数学和数值库、线程和并发库、图像处理库、网络库、任务调度库、正则表达式库等。Boost 库以其高质量而闻名,部分原因是候选库在被纳入 Boost 之前要经过同行评审。
3. 自定义动态数组容器
dynamic_array
3.1 定义
dynamic_array
容器
在 C++ 中,
std::array
和
std::vector
是常用的容器,但它们各有优缺点。
std::array
效率高,但在编译时大小固定;
std::vector
支持运行时动态调整大小,但由于其动态分配机制,存在轻微的性能和存储劣势。
为了结合两者的优点,我们可以创建一个自定义的
dynamic_array
容器。它可以在构造时动态分配一次大小,之后在对象的整个生命周期内保持大小不变。以下是使用示例:
// A dynamic array of four counters initialized with 1.
dynamic_array<unsigned> counters(4U, 1U);
void do_something()
{
// Increment the counters.
std::for_each(std::begin(counters),
std::end(counters),
[](unsigned& u)
{
++u;
});
// It is not possible to resize the dynamic_array.
}
dynamic_array
是一种混合容器,结合了数组的效率和
std::vector
的动态大小调整(尽管是一次性分配)功能。它旨在满足顺序 STL 容器的一般要求,与 STL 基本一致,填补了固定大小的
std::array
和动态的
std::vector
之间的功能空白。
3.2 实现和使用
dynamic_array
以下是
dynamic_array
类的可能实现:
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <memory>
template<typename T,
typename alloc = std::allocator<T>>
class dynamic_array
{
public:
// Type definitions.
typedef alloc allocator_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* iterator;
typedef const T* const_iterator;
typedef T* pointer;
typedef const T* const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
// Constructors.
dynamic_array();
dynamic_array(size_type);
dynamic_array(
size_type,
const value_type&,
const allocator_type& = allocator_type());
dynamic_array(const dynamic_array&);
template<typename input_iterator>
dynamic_array(
input_iterator,
input_iterator,
const allocator_type& = allocator_type());
dynamic_array(
std::initializer_list<T> lst,
const allocator_type& = allocator_type());
// Destructor.
~dynamic_array();
// Iterator members:
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin () const;
const_iterator cend () const;
reverse_iterator rbegin ();
reverse_iterator rend ();
const_reverse_iterator rbegin () const;
const_reverse_iterator rend () const;
const_reverse_iterator crbegin() const;
const_reverse_iterator crend () const;
// Size and capacity.
size_type size() const;
size_type max_size() const;
bool empty() const;
// Element access members.
reference operator[](const size_type);
const_reference operator[](const size_type);
reference front();
const_reference front() const;
reference back ();
const_reference back () const;
reference at(const size_type);
const_reference at(const size_type) const;
// Element manipulation members.
void fill(const value_type&);
void swap(dynamic_array&);
private:
const size_type N;
pointer elems;
// Note: dynamic_array can not be copied
// with operator=().
dynamic_array& operator=(const dynamic_array&);
};
以其中一个构造函数为例,其实现如下:
dynamic_array(size_type count,
const value_type& v,
const allocator_type& a) : N(count)
{
const size_type the_size =
std::max(size_type(1U), N);
elems = allocator_type(a).allocate(the_size);
if(N > size_type(0U))
{
std::fill_n(begin(), N, v);
}
else
{
elems[0U] = value_type();
}
}
dynamic_array
容器满足顺序 STL 容器的大部分一般要求,因此可以与 STL 的标准算法一起使用。例如,以下代码初始化一个
dynamic_array
并计算其字节校验和:
util::dynamic_array<int> values ( { 1, 2, 3 } );
int sum = std::accumulate(values.begin(),
values.end(),
0);
此外,
dynamic_array
还可以与其他函数和类类型一起使用,例如在通信类中:
class communication
{
public:
communication() { }
~communication() { }
bool send(const dynamic_array<std::uint8_t>& cmd);
bool recv(dynamic_array<std::uint8_t>& rsp);
};
3.3 不同容器特性对比
| 容器类型 | 编译时大小 | 运行时调整大小 | 性能和存储 |
|---|---|---|---|
std::array
| 固定 | 不支持 | 效率高 |
std::vector
| 不固定 | 支持 | 有轻微劣势 |
dynamic_array
| 不固定(构造时确定) | 不支持 | 结合两者优点 |
3.4
dynamic_array
使用流程
graph TD;
A[定义 dynamic_array 类型] --> B[创建对象并初始化];
B --> C[使用 STL 算法操作];
C --> D[使用对象进行其他操作];
4. 手动实现 C++ 标准库部分组件
4.1 背景
有些 C++ 编译器可能不提供完整的 C++ 标准库和 STL 实现,或者提供的实现不完整或过时。在这种情况下,如果开发和测试能够满足实时 C++ 的可靠性要求,我们可以手动编写部分组件。
4.2 实现策略
4.2.1 选择存储位置
选择一个单一的位置来存储库头文件和必要的源文件,例如一个根目录结合特定平台库部分的子目录。这样可以简化将路径信息添加到编译器默认搜索路径的过程。
4.2.2 选择实现组件
选择实现的 C++ 库组件主要基于实用性和实现难度。以下是一些建议实现的组件:
- 固定大小的整数类型,包括具有精确位数的类型、至少具有特定位数的类型和至少具有一定位数的最快类型。
- 部分支持
std::array
,可选择不包括反向迭代器。
-
<algorithm>
库中常用且易于实现的函数,如
std::min()
、
std::max()
、
std::for_each()
、
std::fill()
、
std::copy()
、
std::find_if()
等。
-
<type_traits>
库的选定部分,特别是
std::enable_if
和用于检查类型的各种模板,如
std::is_integral
。
- 如果项目中需要进行浮点数基本函数计算,可实现
<cmath>
中的常用数学函数。
4.3 部分组件的实现示例
4.3.1 固定大小整数类型
如果编译器具有 C99 兼容性并支持 C99 固定大小整数类型,可以将这些类型注入到
std
命名空间:
// A partial implementation of <cstdint>
// Include the C99 fixed-size integers.
#include <stdint.h>
namespace std
{
// Types with an exact number of bits.
using ::uint8_t;
using ::uint16_t;
using ::uint32_t;
using ::uint64_t;
// Types with at least a certain number of bits.
using ::uint_least8_t;
using ::uint_least16_t;
using ::uint_least32_t;
using ::uint_least64_t;
// Fastest types with at least a certain
// number of bits.
using ::uint_fast8_t;
using ::uint_fast16_t;
using ::uint_fast32_t;
using ::uint_fast64_t;
}
如果编译器不具有 C99 兼容性,则需要使用平台相关的内置类型(如
char
、
short
、
int
、
long
等)的简单
typedef
来定义这些类型。
4.3.2 部分
std::array
实现
// A partial implementation of <array>
#include <algorithm>
#include <cstddef>
namespace std
{
template <typename T, size_t N>
struct array
{
// Type definitions:
typedef T& reference;
typedef const T& const_reference;
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
// Data elements:
T elems[N];
// iterators:
iterator begin() { return elems; }
iterator end() { return elems + N; }
const_iterator begin() const { return elems; }
const_iterator end() const { return elems + N; }
const_iterator cbegin() const { return elems; }
const_iterator cend() const { return elems + N; }
// Size-related members:
constexpr size_type size() { return N; }
constexpr size_type max_size() { return N; }
constexpr bool empty() { return false; }
// Element access members:
reference operator[](size_type n) { return elems[n]; }
const_reference operator[](size_type n) const { return elems[n]; }
const_reference at(size_type n) const { return elems[n]; }
reference at(size_type n) { return elems[n]; }
reference front() { return elems[0U]; }
const_reference front() const { return elems[0U]; }
reference back() { return elems[N - 1U]; }
const_reference back() const { return elems[N - 1U]; }
T* data() { return elems; }
const T* data() const { return elems; }
// Element manipulation members:
void fill(const T& u) { fill_n(begin(), N, u); }
void swap(const array<T, N>& other) { swap_ranges(begin(), end(), other.begin()); }
};
}
4.3.3
<algorithm>
库部分函数实现
-
std::min()和std::max():
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::min.
template<typename T>
const T& min(const T& a, const T& b)
{
return (a < b ? a : b);
}
// Sample implementation of std::max.
template<typename T>
const T& max(const T& a, const T& b)
{
return (a > b ? a : b);
}
}
-
std::fill():
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::fill.
template<typename forward_iterator,
typename value_type>
void std::fill(forward_iterator first,
forward_iterator last,
const value_type& value)
{
// Fill each element in [first, last) with value.
while(first != last)
{
*first = value;
++first;
}
}
}
-
std::for_each():
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::for_each.
template<typename iterator_type,
typename function_type>
function_type std::for_each(iterator_type first,
iterator_type last,
function_type function)
{
// Apply function to each element in [first, last).
while(first != last)
{
function(*first);
++first;
}
return function;
}
}
-
std::find_if():
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::find_if.
template<typename iterator_type,
typename predicate_type>
iterator_type std::find_if(iterator_type first,
iterator_type last,
predicate_type predicate)
{
// Find the first element satisfying predicate.
while(
(first != last)
&& (false == predicate(*first)))
{
++first;
}
return first;
}
}
4.3.4
<type_traits>
库部分实现
// Implement part of <type_traits>
namespace std
{
template<typename integral_value_type,
integral_value_type integral_value>
struct integral_constant
{
typedef integral_value_type value_type;
static constexpr value_type my_value =
integral_value;
typedef
integral_constant<value_type, my_value> type;
operator value_type() const
{
return my_value;
}
};
typedef integral_constant<bool, true>
true_type;
typedef integral_constant<bool, false> false_type;
}
4.3.5
<cmath>
库部分实现
// Implement part of <cmath>
#include <math.h>
namespace std
{
// Overwrites of the square root function.
inline float sqrt(float x)
{
return ::sqrtf(x);
}
inline double sqrt(double x)
{
return ::sqrt(x);
}
inline long double sqrt(long double x)
{
return ::sqrtl(x);
}
// Overwrites of the sine function.
inline float sin(float x)
{
return ::sinf(x);
}
inline double sin(double x)
{
return ::sin(x);
}
inline long double sin(long double x)
{
return ::sinl(x);
}
// Overwrites of the exponent function.
inline float exp(float x)
{
return ::expf(x);
}
inline double exp(double x)
{
return ::exp(x);
}
inline long double exp(long double x)
{
return ::expl(x);
}
// ...and numerous other elementary functions.
}
4.4 手动实现标准库组件流程
graph TD;
A[确定缺失组件] --> B[选择存储位置];
B --> C[选择实现组件];
C --> D[编写组件代码];
D --> E[测试和调试];
通过以上内容,我们了解了 Boost 中的循环缓冲区类、自定义
dynamic_array
容器以及手动实现 C++ 标准库部分组件的方法,这些技术可以帮助我们在不同的编程场景中更好地使用 C++ 语言。
5. 手动实现组件的详细分析
5.1 固定大小整数类型实现分析
在实现固定大小整数类型时,根据编译器是否支持 C99 兼容性有不同的处理方式。
-
支持 C99 兼容性
:可以直接将 C99 固定大小整数类型注入到
std
命名空间,这种方式简单直接,利用了编译器已有的支持,代码如下:
// A partial implementation of <cstdint>
// Include the C99 fixed-size integers.
#include <stdint.h>
namespace std
{
// Types with an exact number of bits.
using ::uint8_t;
using ::uint16_t;
using ::uint32_t;
using ::uint64_t;
// Types with at least a certain number of bits.
using ::uint_least8_t;
using ::uint_least16_t;
using ::uint_least32_t;
using ::uint_least64_t;
// Fastest types with at least a certain
// number of bits.
using ::uint_fast8_t;
using ::uint_fast16_t;
using ::uint_fast32_t;
using ::uint_fast64_t;
}
-
不支持 C99 兼容性
:需要使用平台相关的内置类型(如
char、short、int、long等)的简单typedef来定义这些类型。但这种方式存在轻微的可移植性问题,因为内置类型的宽度是编译器依赖的。不过,对于特定平台,只需设置一次这些类型,之后可以通过不同目录分离处理器特定版本的头文件,或使用预处理器定义在更大的头文件中实现分离。
5.2
std::array
部分实现分析
部分实现的
std::array
不包括反向迭代器,但满足了大部分基本功能。它使用了
std::size_t
和
std::ptrdiff_t
等标准库类型,以及
std::fill_n()
和
std::swap_ranges()
等算法。以下是部分关键代码分析:
// A partial implementation of <array>
#include <algorithm>
#include <cstddef>
namespace std
{
template <typename T, size_t N>
struct array
{
// 类型定义
typedef T& reference;
typedef const T& const_reference;
typedef T* iterator;
typedef const T* const_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
// 数据元素
T elems[N];
// 迭代器
iterator begin() { return elems; }
iterator end() { return elems + N; }
const_iterator begin() const { return elems; }
const_iterator end() const { return elems + N; }
const_iterator cbegin() const { return elems; }
const_iterator cend() const { return elems + N; }
// 大小相关成员
constexpr size_type size() { return N; }
constexpr size_type max_size() { return N; }
constexpr bool empty() { return false; }
// 元素访问成员
reference operator[](size_type n) { return elems[n]; }
const_reference operator[](size_type n) const { return elems[n]; }
const_reference at(size_type n) const { return elems[n]; }
reference at(size_type n) { return elems[n]; }
reference front() { return elems[0U]; }
const_reference front() const { return elems[0U]; }
reference back() { return elems[N - 1U]; }
const_reference back() const { return elems[N - 1U]; }
T* data() { return elems; }
const T* data() const { return elems; }
// 元素操作成员
void fill(const T& u) { fill_n(begin(), N, u); }
void swap(const array<T, N>& other) { swap_ranges(begin(), end(), other.begin()); }
};
}
- 类型定义 :定义了各种常用的类型别名,方便使用。
-
迭代器
:提供了
begin()和end()等迭代器函数,用于遍历数组元素。 -
大小相关成员
:通过
size()和max_size()函数返回数组的大小,empty()函数判断数组是否为空。 -
元素访问成员
:提供了
operator[]和at()等函数用于访问数组元素。 -
元素操作成员
:
fill()函数用于用指定值填充数组,swap()函数用于交换两个数组的元素。
5.3
<algorithm>
库部分函数实现分析
5.3.1
std::min()
和
std::max()
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::min.
template<typename T>
const T& min(const T& a, const T& b)
{
return (a < b ? a : b);
}
// Sample implementation of std::max.
template<typename T>
const T& max(const T& a, const T& b)
{
return (a > b ? a : b);
}
}
这两个函数通过模板实现,比较两个元素的大小并返回较小或较大的元素,逻辑简单直接。
5.3.2
std::fill()
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::fill.
template<typename forward_iterator,
typename value_type>
void std::fill(forward_iterator first,
forward_iterator last,
const value_type& value)
{
// Fill each element in [first, last) with value.
while(first != last)
{
*first = value;
++first;
}
}
}
该函数使用迭代器遍历指定范围
[first, last)
,并将每个元素赋值为指定的值。
5.3.3
std::for_each()
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::for_each.
template<typename iterator_type,
typename function_type>
function_type std::for_each(iterator_type first,
iterator_type last,
function_type function)
{
// Apply function to each element in [first, last).
while(first != last)
{
function(*first);
++first;
}
return function;
}
}
std::for_each()
函数对指定范围
[first, last)
内的每个元素应用给定的函数,并返回该函数对象。
5.3.4
std::find_if()
// Implement part of <algorithm>
namespace std
{
// Sample implementation of std::find_if.
template<typename iterator_type,
typename predicate_type>
iterator_type std::find_if(iterator_type first,
iterator_type last,
predicate_type predicate)
{
// Find the first element satisfying predicate.
while(
(first != last)
&& (false == predicate(*first)))
{
++first;
}
return first;
}
}
该函数在指定范围
[first, last)
内查找第一个满足给定谓词的元素,并返回该元素的迭代器。
5.4
<type_traits>
库部分实现分析
// Implement part of <type_traits>
namespace std
{
template<typename integral_value_type,
integral_value_type integral_value>
struct integral_constant
{
typedef integral_value_type value_type;
static constexpr value_type my_value =
integral_value;
typedef
integral_constant<value_type, my_value> type;
operator value_type() const
{
return my_value;
}
};
typedef integral_constant<bool, true>
true_type;
typedef integral_constant<bool, false> false_type;
}
通过定义
integral_constant
结构体,可以方便地创建编译时常量。
true_type
和
false_type
是基于
integral_constant
的特化,用于表示布尔常量。利用这些基础结构,可以编写许多编译时模板,如
std::is_integral
等。
5.5
<cmath>
库部分实现分析
// Implement part of <cmath>
#include <math.h>
namespace std
{
// Overwrites of the square root function.
inline float sqrt(float x)
{
return ::sqrtf(x);
}
inline double sqrt(double x)
{
return ::sqrt(x);
}
inline long double sqrt(long double x)
{
return ::sqrtl(x);
}
// Overwrites of the sine function.
inline float sin(float x)
{
return ::sinf(x);
}
inline double sin(double x)
{
return ::sin(x);
}
inline long double sin(long double x)
{
return ::sinl(x);
}
// Overwrites of the exponent function.
inline float exp(float x)
{
return ::expf(x);
}
inline double exp(double x)
{
return ::exp(x);
}
inline long double exp(long double x)
{
return ::expl(x);
}
// ...and numerous other elementary functions.
}
<cmath>
库的部分实现通过内联函数将 C 标准库中的数学函数包装到
std
命名空间中,为 C++ 提供了与 C 兼容的数学函数接口。
5.6 手动实现组件的优缺点总结
| 优点 | 缺点 |
|---|---|
| 可以在编译器不提供完整标准库时使用所需功能 | 手动实现可能存在错误,需要进行充分测试 |
| 可以根据实际需求选择实现部分组件,减少代码量 | 部分实现可能不完整,无法涵盖标准库的所有功能 |
| 加深对标准库实现原理的理解 | 对于复杂组件的实现难度较大 |
6. 总结与应用建议
6.1 总结
本文介绍了 Boost 中的循环缓冲区类、自定义
dynamic_array
容器以及手动实现 C++ 标准库部分组件的方法。
-
Boost 循环缓冲区类
:提供了支持迭代器且符合 STL 标准的循环缓冲区功能,使用简单。
-
自定义
dynamic_array
容器
:结合了
std::array
和
std::vector
的优点,在构造时动态分配大小,之后保持不变,可与 STL 算法一起使用。
-
手动实现标准库组件
:在编译器不提供完整标准库时,可以根据实用性和实现难度选择部分组件进行手动实现。
6.2 应用建议
-
选择合适的容器
:根据具体需求选择
std::array、std::vector或dynamic_array容器。如果需要固定大小的容器,使用std::array;如果需要动态调整大小,使用std::vector;如果需要在构造时动态分配大小且之后保持不变,使用dynamic_array。 -
手动实现标准库组件
:在编译器不提供完整标准库时,优先选择实现常用且易于实现的组件,如固定大小整数类型、部分
std::array实现、<algorithm>库部分函数等。在实现过程中,要注意可移植性和代码的正确性,进行充分的测试和调试。
通过合理运用这些技术,可以在不同的编程场景中更好地使用 C++ 语言,提高编程效率和代码质量。
超级会员免费看
2686

被折叠的 条评论
为什么被折叠?



