探索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的相关内容。
在这里插入图片描述

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion Long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值