探索C++ STL的设计方式:将算法与数据结构分离

一、简介

本文介绍STL的设计方式,以及如何设计自己的组件,使其能够充分利用STL的功能。

STL的设计旨在将算法与数据结构分离。

算法包括:

  • 头文件<algorithm>中的算法。
  • 当我们的需求无法通过标准算法解决时,我们自己编写的算法。

数据包括:

  • 标准STL容器,如std::mapstd::vector
  • C 数组。
  • 用户定义的集合。
  • 上述内容的任何子部分。

数据甚至可以从流中获取。

通过“迭代器”接口,已经实现了将算法与数据结构分离的目的。
在这里插入图片描述

为了从各种算法的众多优势中受益,数据必须具备迭代器接口。下面介绍了如何为不同类型的数据实现迭代器。

二、STL容器

通过以下方式可以获得迭代器:

  • begin()end()
  • rbegin()rend()用于反向迭代器。
  • cbegin()cend()(或者const容器上的begin()end())用于常量迭代器。
  • crbegin()crend()(或者const容器上的rbegin()rend())用于常量反向迭代器。

三、C数组

对于C数组,指针扮演迭代器的角色。

int myInts[100];

std::for_each(myInts, myInts + 100, doSomething);

严格来说,myInts不是指针而是数组,但它仍然提供对数组的第一个元素的访问,而myInts + 100指向“结束后”的地址,符合begin-end的语义。

因此,C数组可以与算法一起使用,在旧代码中非常有帮助。

需要注意的是,自C++11以来引入了一种新的统一语法,使用std::begin(和std::end)自由函数(而不是类方法)。它们可以统一地用于任何具有可以无参数调用的begin(或end)方法的类型,并且也可以用于C数组。

下面的代码示例说明了这种统一性:

int myInts[100];
std::vector<int> vec(100, 0); // 大小为100且初始化为0

std::for_each(std::begin(vec), std::end(vec), doSomething);
std::for_each(std::begin(myInts), std::end(myInts), doSomething);

这使得使用C数组变得更加简单,并且对于通用代码非常方便。

需要注意的是,对于C数组,必须显式地写出std命名空间,因为它无法使用ADL,但对于vector可以省略std命名空间。

四、用户定义的集合

有时会编写自己的集合来满足特定领域的需求。以用户定义的FlowCollection类为例,该类表示一组财务流量。根据上面所见,为了能够使用算法,它需要提供迭代器。那么,该如何做呢?

4.1、使用标准集合的typedef

每当想编写一个集合时,先考虑一下是否有标准集合可以满足需求。这样可以减少需要编写的代码量。在很多情况下,标准集合就足够了,可以使用typedef为它加上一个领域名称。例如:

using FlowCollection = std::vector<Flow>;

这样,就可以免费获得所有迭代器以及std::vector的所有功能,同时还有一个带有领域名称的类型。

4.2、重用标准迭代器

如果集合确实需要领域功能,或者只想要标准容器提供的部分功能,可能需要定义一个包装标准容器的类。在这种情况下,可以使用标准容器的迭代器来实现迭代器:

// 接口

class FlowCollection
{
public:
    // ...领域接口...

    // 允许访问数据的迭代器
    using const_iterator = std::vector<Flow>::const_iterator;
    const_iterator begin() const;
    const_iterator end() const;

    // 允许修改数据的迭代器
    using iterator = std::vector<Flow>::iterator;
    iterator begin();
    iterator end();

    // 其他迭代器...

private:
    std::vector<Flow> m_flows;
    // ...领域数据...
};


// 实现

FlowCollection::iterator FlowCollection::begin()
{
    return m_flows.begin();
}

4.3、实现自己的迭代器

如果集合的复杂性超过了前面两种技术的范围,可能需要实现自己的迭代器。这样做更加复杂,超出了本文的范围,并且只有在非常罕见的情况下才需要这样做。

五、总结

这就是STL在当今C++中的地位。如果想要一窥STL在未来的发展趋势(以及如何立即开始使用它),可以看看ranges的相关内容。
在这里插入图片描述

相关推荐

  1. 数据结构算法-分治算法

    2024-06-11 10:34:05       16 阅读
  2. 数据结构算法===分治算法

    2024-06-11 10:34:05       12 阅读
  3. 算法】【数据结构算法数据结构关系

    2024-06-11 10:34:05       33 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-11 10:34:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-11 10:34:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-11 10:34:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-11 10:34:05       18 阅读

热门阅读

  1. 【Redis】Redis的数据淘汰策略有哪些

    2024-06-11 10:34:05       10 阅读
  2. SQL的执行顺序

    2024-06-11 10:34:05       7 阅读
  3. Web前端与PHP:深度解析与未来展望

    2024-06-11 10:34:05       10 阅读
  4. 特别名词Test Paper3

    2024-06-11 10:34:05       9 阅读
  5. 微信小程序真机调试连不上

    2024-06-11 10:34:05       7 阅读
  6. MATLAB 论文绘图规范标注

    2024-06-11 10:34:05       11 阅读
  7. 模块间通信

    2024-06-11 10:34:05       7 阅读