第29章 自定义标准库

标准库自定义概述

C++标准库设计为可扩展和可定制的,通过各种机制允许开发者根据特定需求自定义标准库组件。自定义标准库的主要方式包括:

  • 自定义分配器:控制内存分配策略
  • 自定义迭代器:实现特定的数据遍历方式
  • 扩展算法:基于标准算法框架实现自定义算法
  • 适配器模式:包装现有组件以提供新接口
  • 特化标准模板:为特定类型定制标准库行为
  • 概念约束:使用C++20概念限制模板参数

自定义分配器

分配器是标准库中用于内存管理的组件,为容器提供内存分配和释放功能。自定义分配器可以优化特定场景下的内存使用。

分配器接口

一个符合标准的分配器需要实现以下核心接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <memory>
#include <cstddef>

template <typename T>
class CustomAllocator {
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;

// 构造函数
CustomAllocator() noexcept = default;

// 拷贝构造函数(不同类型)
template <typename U>
CustomAllocator(const CustomAllocator<U>&) noexcept {}

// 分配内存
T* allocate(size_type n) {
if (n > max_size()) {
throw std::bad_alloc();
}
// 自定义内存分配逻辑
return static_cast<T*>(::operator new(n * sizeof(T)));
}

// 释放内存
void deallocate(T* p, size_type) noexcept {
// 自定义内存释放逻辑
::operator delete(p);
}

// 最大可分配大小
size_type max_size() const noexcept {
return static_cast<size_type>(-1) / sizeof(T);
}

// 比较运算符
template <typename U>
bool operator==(const CustomAllocator<U>&) const noexcept {
return true;
}

template <typename U>
bool operator!=(const CustomAllocator<U>&) const noexcept {
return false;
}
};

带状态的分配器

分配器可以包含状态,例如内存池或线程本地存储:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <memory>
#include <vector>
#include <mutex>

class MemoryPool {
public:
void* allocate(size_t size) {
std::lock_guard<std::mutex> lock(mutex_);
// 内存池分配逻辑
return ::operator new(size);
}

void deallocate(void* p, size_t size) {
std::lock_guard<std::mutex> lock(mutex_);
// 内存池释放逻辑
::operator delete(p);
}

private:
std::mutex mutex_;
// 内存池数据结构
};

template <typename T>
class PoolAllocator {
public:
using value_type = T;

PoolAllocator(MemoryPool& pool) noexcept : pool_(&pool) {}

template <typename U>
PoolAllocator(const PoolAllocator<U>& other) noexcept : pool_(other.pool_) {}

T* allocate(std::size_t n) {
return static_cast<T*>(pool_->allocate(n * sizeof(T)));
}

void deallocate(T* p, std::size_t n) noexcept {
pool_->deallocate(p, n * sizeof(T));
}

template <typename U>
bool operator==(const PoolAllocator<U>& other) const noexcept {
return pool_ == other.pool_;
}

template <typename U>
bool operator!=(const PoolAllocator<U>& other) const noexcept {
return !(*this == other);
}

// 用于rebind的嵌套类型
template <typename U>
struct rebind {
using other = PoolAllocator<U>;
};

private:
template <typename> friend class PoolAllocator;
MemoryPool* pool_;
};

// 使用示例
int main() {
MemoryPool pool;
std::vector<int, PoolAllocator<int>> vec(PoolAllocator<int>(pool));
vec.push_back(42);
return 0;
}

分配器使用场景

  1. 内存池:减少频繁内存分配的开销
  2. 对齐优化:为特定类型提供对齐保证
  3. 统计和跟踪:监控内存使用情况
  4. 线程本地存储:避免线程间竞争
  5. 受限环境:在内存有限的环境中优化使用

自定义迭代器

迭代器是连接容器和算法的桥梁,自定义迭代器可以为特殊数据结构提供标准的遍历接口。

迭代器类别

C++标准定义了五种迭代器类别,按功能从弱到强排序:

  1. 输入迭代器:只读,单遍,不可重复
  2. 输出迭代器:只写,单遍,不可重复
  3. 前向迭代器:可读写,多遍,可重复
  4. 双向迭代器:前向迭代器 + 反向遍历
  5. 随机访问迭代器:双向迭代器 + 随机访问

迭代器实现

下面实现一个简单的双向迭代器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iterator>

// 简单链表节点
template <typename T>
struct Node {
T value;
Node* next;
Node* prev;

Node(const T& v) : value(v), next(nullptr), prev(nullptr) {}
};

// 链表迭代器
template <typename T>
class ListIterator {
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
using iterator_category = std::bidirectional_iterator_tag;

ListIterator(Node<T>* node) : current(node) {}

// 解引用
reference operator*() const {
return current->value;
}

pointer operator->() const {
return &(current->value);
}

// 前缀递增
ListIterator& operator++() {
current = current->next;
return *this;
}

// 后缀递增
ListIterator operator++(int) {
ListIterator tmp = *this;
++(*this);
return tmp;
}

// 前缀递减
ListIterator& operator--() {
current = current->prev;
return *this;
}

// 后缀递减
ListIterator operator--(int) {
ListIterator tmp = *this;
--(*this);
return tmp;
}

// 比较运算符
bool operator==(const ListIterator& other) const {
return current == other.current;
}

bool operator!=(const ListIterator& other) const {
return !(*this == other);
}

private:
Node<T>* current;
};

// 常量迭代器
template <typename T>
class ConstListIterator {
// 类似实现,但返回const引用
};

迭代器适配器

迭代器适配器是基于现有迭代器构建的新迭代器,例如反向迭代器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
template <typename Iterator>
class ReverseIterator {
public:
using value_type = typename std::iterator_traits<Iterator>::value_type;
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using pointer = typename std::iterator_traits<Iterator>::pointer;
using reference = typename std::iterator_traits<Iterator>::reference;
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;

ReverseIterator(Iterator it) : current(it) {}

reference operator*() const {
Iterator tmp = current;
--tmp;
return *tmp;
}

ReverseIterator& operator++() {
--current;
return *this;
}

ReverseIterator operator++(int) {
ReverseIterator tmp = *this;
--current;
return tmp;
}

ReverseIterator& operator--() {
++current;
return *this;
}

ReverseIterator operator--(int) {
ReverseIterator tmp = *this;
++current;
return tmp;
}

bool operator==(const ReverseIterator& other) const {
return current == other.current;
}

bool operator!=(const ReverseIterator& other) const {
return !(*this == other);
}

private:
Iterator current;
};

自定义算法

标准库算法是通用的,但在某些场景下需要定制化的算法实现。

基于标准算法的扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <algorithm>
#include <vector>
#include <functional>

// 自定义算法:查找第一个满足多个条件的元素
template <typename InputIt, typename... Predicates>
auto find_if_all(InputIt first, InputIt last, Predicates&&... preds) {
return std::find_if(first, last, [&](const auto& value) {
return (std::invoke(preds, value) && ...);
});
}

// 自定义算法:带索引的for_each
template <typename InputIt, typename UnaryFunction>
UnaryFunction for_each_with_index(InputIt first, InputIt last, UnaryFunction f) {
std::size_t index = 0;
for (; first != last; ++first, ++index) {
f(*first, index);
}
return f;
}

// 使用示例
int main() {
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

// 查找第一个大于5且为偶数的元素
auto it = find_if_all(v.begin(), v.end(),
[](int x) { return x > 5; },
[](int x) { return x % 2 == 0; });

// 带索引遍历
for_each_with_index(v.begin(), v.end(),
[](int value, std::size_t index) {
std::cout << "Index " << index << ": " << value << std::endl;
});

return 0;
}

并行算法实现

C++17引入了并行算法,我们可以基于此实现自定义并行算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <execution>
#include <algorithm>
#include <vector>
#include <numeric>

// 自定义并行算法:并行变换并累加
template <typename ExecutionPolicy, typename InputIt, typename OutputIt,
typename UnaryOp, typename T>
T transform_reduce(ExecutionPolicy&& policy,
InputIt first, InputIt last,
OutputIt result,
UnaryOp op,
T init) {
// 并行变换
std::transform(policy, first, last, result, op);
// 并行累加
return std::reduce(policy, result, result + std::distance(first, last), init);
}

// 使用示例
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::vector<int> transformed(v.size());

// 并行计算平方和
int sum_of_squares = transform_reduce(
std::execution::par, // 并行执行策略
v.begin(), v.end(),
transformed.begin(),
[](int x) { return x * x; },
0
);

return 0;
}

适配器模式

适配器模式可以包装现有标准库组件,为其提供新的接口或行为。

容器适配器

标准库中的stackqueuepriority_queue都是容器适配器,我们可以实现自定义适配器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <deque>
#include <vector>
#include <algorithm>

// 自定义容器适配器:固定大小的队列
template <typename T, typename Container = std::deque<T>>
class FixedSizeQueue {
public:
using container_type = Container;
using value_type = typename Container::value_type;
using size_type = typename Container::size_type;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;

explicit FixedSizeQueue(size_type max_size) : max_size_(max_size) {}

bool empty() const { return c_.empty(); }
size_type size() const { return c_.size(); }
size_type max_size() const { return max_size_; }

reference front() { return c_.front(); }
const_reference front() const { return c_.front(); }

reference back() { return c_.back(); }
const_reference back() const { return c_.back(); }

void push(const value_type& value) {
if (size() >= max_size_) {
c_.pop_front();
}
c_.push_back(value);
}

void push(value_type&& value) {
if (size() >= max_size_) {
c_.pop_front();
}
c_.push_back(std::move(value));
}

void pop() {
c_.pop_front();
}

private:
Container c_;
size_type max_size_;
};

// 使用示例
int main() {
FixedSizeQueue<int> q(3);
q.push(1);
q.push(2);
q.push(3);
q.push(4); // 会自动移除最早的元素1

while (!q.empty()) {
std::cout << q.front() << ' '; // 输出 2 3 4
q.pop();
}

return 0;
}

函数适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <functional>

// 函数适配器:带缓存的函数
template <typename Func>
class CachedFunction {
public:
explicit CachedFunction(Func func) : func_(std::move(func)) {}

template <typename... Args>
auto operator()(Args&&... args) {
using Key = std::tuple<std::decay_t<Args>...>;
Key key(std::forward<Args>(args)...);

auto it = cache_.find(key);
if (it != cache_.end()) {
return it->second;
}

auto result = func_(std::forward<Args>(args)...);
cache_[key] = result;
return result;
}

void clear_cache() {
cache_.clear();
}

private:
Func func_;
std::unordered_map<std::tuple<>, decltype(func_())> cache_; // 简化版本
};

// 辅助函数
template <typename Func>
auto make_cached(Func&& func) {
return CachedFunction<std::decay_t<Func>>(std::forward<Func>(func));
}

特化标准模板

为特定类型特化标准库模板可以定制其行为。

特化std::hash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <functional>
#include <string>

// 为自定义类型特化std::hash
struct Point {
int x;
int y;

bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};

namespace std {
template <>
struct hash<Point> {
size_t operator()(const Point& p) const {
size_t h1 = std::hash<int>()(p.x);
size_t h2 = std::hash<int>()(p.y);
// 组合哈希值
return h1 ^ (h2 << 1);
}
};
}

// 使用示例
int main() {
std::unordered_set<Point> points;
points.insert({1, 2});
points.insert({3, 4});

return 0;
}

特化std::less

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <functional>
#include <set>
#include <string>

// 为自定义类型特化std::less
struct Person {
std::string name;
int age;
};

namespace std {
template <>
struct less<Person> {
bool operator()(const Person& a, const Person& b) const {
// 先按年龄排序,再按姓名排序
if (a.age != b.age) {
return a.age < b.age;
}
return a.name < b.name;
}
};
}

// 使用示例
int main() {
std::set<Person> people;
people.insert({"Alice", 30});
people.insert({"Bob", 25});
people.insert({"Charlie", 30});

return 0;
}

概念约束

C++20引入的概念(Concepts)可以为模板参数提供更清晰的约束。

定义自定义概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <concepts>
#include <iterator>

// 自定义概念:可增量的
template <typename T>
concept Incrementable = requires(T t) {
{ ++t } -> std::same_as<T&>;
{ t++ } -> std::same_as<T>;
};

// 自定义概念:可打印的
template <typename T>
concept Printable = requires(std::ostream& os, const T& t) {
{ os << t } -> std::same_as<std::ostream&>;
};

// 使用概念约束的函数
template <Incrementable T>
void increment_n(T& value, int n) {
for (int i = 0; i < n; ++i) {
++value;
}
}

// 组合多个概念
template <typename T>
concept Iterable = requires(T t) {
{ std::begin(t) } -> std::input_or_output_iterator;
{ std::end(t) } -> std::input_or_output_iterator;
};

template <typename T>
concept IterableAndPrintable = Iterable<T> && Printable<typename std::iter_value_t<decltype(std::begin(std::declval<T>()))>>;

// 使用组合概念
template <IterableAndPrintable T>
void print_all(const T& container) {
for (const auto& element : container) {
std::cout << element << ' ';
}
std::cout << std::endl;
}

概念与标准库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <concepts>
#include <vector>
#include <list>
#include <set>

// 标准库概念的使用
template <std::ranges::range R>
void process_range(R&& range) {
// 处理范围
for (auto&& element : range) {
// 处理元素
}
}

template <std::sortable S>
void sort_container(S& container) {
std::sort(std::begin(container), std::end(container));
}

// 使用示例
int main() {
std::vector<int> v = {3, 1, 4, 1, 5};
process_range(v);
sort_container(v);

std::list<int> l = {5, 3, 1};
process_range(l);
// sort_container(l); // 错误:list不支持随机访问

return 0;
}

自定义类型特征

类型特征(Type Traits)是编译期信息,用于查询类型的属性。

自定义类型特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <type_traits>

// 自定义类型特征:检查是否为指针类型(包括智能指针)
template <typename T>
struct is_smart_pointer : std::false_type {};

// 特化各种智能指针
template <typename T>
struct is_smart_pointer<std::unique_ptr<T>> : std::true_type {};

template <typename T>
struct is_smart_pointer<std::shared_ptr<T>> : std::true_type {};

template <typename T>
struct is_smart_pointer<std::weak_ptr<T>> : std::true_type {};

// 辅助变量模板
template <typename T>
inline constexpr bool is_smart_pointer_v = is_smart_pointer<T>::value;

// 辅助概念(C++20)
template <typename T>
concept SmartPointer = is_smart_pointer_v<T>;

// 使用示例
template <typename T>
void process_pointer(T ptr) {
if constexpr (is_smart_pointer_v<T>) {
// 处理智能指针
if (ptr) {
// 使用ptr
}
} else if constexpr (std::is_pointer_v<T>) {
// 处理原始指针
if (ptr) {
// 使用ptr
}
} else {
// 处理非指针类型
}
}

类型特征组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <type_traits>

// 组合多个类型特征
template <typename T>
struct is_integral_or_enum : std::bool_constant<
std::is_integral_v<T> || std::is_enum_v<T>
> {};

template <typename T>
inline constexpr bool is_integral_or_enum_v = is_integral_or_enum<T>::value;

// 类型变换特征
template <typename T>
struct remove_cvref {
using type = std::remove_cv_t<std::remove_reference_t<T>>;
};

template <typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

自定义工具类

作用域守卫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <functional>

// 作用域守卫:在作用域结束时执行指定操作
class ScopeGuard {
public:
template <typename Func>
explicit ScopeGuard(Func&& func)
: func_(std::forward<Func>(func)), active_(true) {}

ScopeGuard(ScopeGuard&& other) noexcept
: func_(std::move(other.func_)), active_(other.active_) {
other.active_ = false;
}

~ScopeGuard() {
if (active_) {
func_();
}
}

// 禁止拷贝
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard& operator=(ScopeGuard&&) = delete;

// 手动取消
void dismiss() noexcept {
active_ = false;
}

private:
std::function<void()> func_;
bool active_;
};

// 辅助宏
#define SCOPE_EXIT auto scope_guard_##__LINE__ = ScopeGuard([&]()

// 使用示例
int main() {
FILE* file = fopen("test.txt", "w");
if (!file) return 1;

// 确保文件被关闭
SCOPE_EXIT {
fclose(file);
});

// 使用文件
fprintf(file, "Hello, World!");

return 0;
}

类型擦除容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <memory>
#include <vector>
#include <functional>

// 类型擦除接口
class AnyValue {
public:
virtual ~AnyValue() = default;
virtual std::unique_ptr<AnyValue> clone() const = 0;
};

// 类型擦除实现
template <typename T>
class AnyValueImpl : public AnyValue {
public:
explicit AnyValueImpl(T value) : value_(std::move(value)) {}

std::unique_ptr<AnyValue> clone() const override {
return std::make_unique<AnyValueImpl<T>>(value_);
}

T& get() { return value_; }
const T& get() const { return value_; }

private:
T value_;
};

// 类型擦除容器
class HeterogeneousVector {
public:
template <typename T>
void push_back(T value) {
values_.push_back(std::make_unique<AnyValueImpl<T>>(std::move(value)));
}

template <typename T>
T& get(size_t index) {
auto* impl = dynamic_cast<AnyValueImpl<T>*>(values_[index].get());
if (!impl) {
throw std::bad_cast();
}
return impl->get();
}

size_t size() const {
return values_.size();
}

private:
std::vector<std::unique_ptr<AnyValue>> values_;
};

最佳实践

自定义标准库组件的原则

  1. 遵循接口:严格按照标准库接口设计,确保兼容性
  2. 注重性能:自定义组件应在特定场景下提供性能优势
  3. 保持可移植性:避免依赖平台特定特性
  4. 全面测试:确保与标准库算法和容器配合正常
  5. 文档清晰:详细说明自定义组件的用途和限制
  6. 异常安全:提供强异常安全保证
  7. 资源管理:正确管理所有资源,避免泄漏

性能考虑

  1. 内存局部性:自定义分配器应优化内存布局
  2. 减少开销:迭代器操作应尽可能高效
  3. 避免动态分配:在性能关键路径上减少内存分配
  4. 编译期计算:利用模板和constexpr提高性能
  5. 并行处理:对于大型操作,考虑并行实现

安全性考虑

  1. 类型安全:使用模板和概念确保类型安全
  2. 边界检查:在适当位置添加边界检查
  3. 异常处理:正确处理和传播异常
  4. 资源管理:使用RAII模式管理资源
  5. 线程安全:在多线程环境中确保安全

实际应用案例

内存池分配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 简单内存池实现
class MemoryPool {
public:
MemoryPool(size_t block_size, size_t num_blocks)
: block_size_(block_size), num_blocks_(num_blocks) {
// 分配大块内存
pool_ = static_cast<char*>(::operator new(block_size * num_blocks));
// 初始化自由块链表
for (size_t i = 0; i < num_blocks - 1; ++i) {
*reinterpret_cast<char**>(pool_ + i * block_size) = pool_ + (i + 1) * block_size;
}
*reinterpret_cast<char**>(pool_ + (num_blocks - 1) * block_size) = nullptr;
free_list_ = pool_;
}

~MemoryPool() {
::operator delete(pool_);
}

void* allocate() {
if (!free_list_) {
return nullptr; // 内存池耗尽
}
void* ptr = free_list_;
free_list_ = *reinterpret_cast<char**>(free_list_);
return ptr;
}

void deallocate(void* ptr) {
if (!ptr) return;
// 将内存块放回自由链表
*reinterpret_cast<char**>(ptr) = free_list_;
free_list_ = static_cast<char*>(ptr);
}

private:
size_t block_size_;
size_t num_blocks_;
char* pool_;
char* free_list_;
};

// 使用内存池的分配器
template <typename T>
class PoolAllocator {
public:
using value_type = T;

PoolAllocator(MemoryPool& pool) : pool_(&pool) {}

template <typename U>
PoolAllocator(const PoolAllocator<U>& other) : pool_(other.pool_) {}

T* allocate(size_t n) {
if (n != 1) {
throw std::bad_alloc(); // 只支持分配单个对象
}
return static_cast<T*>(pool_->allocate());
}

void deallocate(T* p, size_t) {
pool_->deallocate(p);
}

private:
template <typename> friend class PoolAllocator;
MemoryPool* pool_;
};

自定义范围适配器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <ranges>
#include <vector>
#include <iostream>

// 自定义范围适配器:步长范围
template <typename T>
class StepRange {
public:
StepRange(T start, T end, T step)
: start_(start), end_(end), step_(step) {}

class Iterator {
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = const T*;
using reference = const T&;
using iterator_category = std::input_iterator_tag;

Iterator(T value, T step) : value_(value), step_(step) {}

reference operator*() const { return value_; }
pointer operator->() const { return &value_; }

Iterator& operator++() {
value_ += step_;
return *this;
}

Iterator operator++(int) {
Iterator tmp = *this;
++(*this);
return tmp;
}

bool operator==(const Iterator& other) const {
return value_ == other.value_;
}

bool operator!=(const Iterator& other) const {
return !(*this == other);
}

private:
T value_;
T step_;
};

Iterator begin() const {
return Iterator(start_, step_);
}

Iterator end() const {
return Iterator(end_, step_);
}

private:
T start_;
T end_;
T step_;
};

// 辅助函数
template <typename T>
auto step_range(T start, T end, T step) {
return StepRange<T>(start, end, step);
}

// 使用示例
int main() {
// 生成0到10,步长为2的序列
for (int i : step_range(0, 10, 2)) {
std::cout << i << ' '; // 输出 0 2 4 6 8
}

return 0;
}

小结

自定义C++标准库组件是一项高级技术,需要深入理解标准库的设计原理和接口规范。通过合理的自定义,可以:

  1. 优化性能:针对特定场景定制内存管理和算法实现
  2. 扩展功能:为标准库添加新的能力和接口
  3. 提高可维护性:封装复杂逻辑,提供清晰的接口
  4. 增强安全性:添加类型检查和边界验证
  5. 适应特殊环境:在受限环境中提供标准库功能

自定义标准库组件时,应遵循以下原则:

  • 保持兼容性:严格遵循标准接口,确保与现有代码配合
  • 注重质量:提供全面的测试和文档
  • 权衡利弊:只有在确实需要时才自定义,避免过度设计
  • 持续学习:关注C++标准的更新,利用新特性改进实现

通过本章的学习,读者应该掌握了自定义标准库组件的核心技术,能够根据具体需求设计和实现高质量的自定义组件,从而提升C++程序的性能和可维护性。